shell: don't abuse link_layer for keeping track of input panel surfaces
Input panel surfaces were kept in a list by using layer_link of
weston_surface. This was pretty hacky and resulted in the bug that
an input panel surface was not removed from the list if it was unmapped
at the time of destruction.
This patch wraps the surface in a new input_panel_surface struct and
properly handles destruction with a signal listener.
diff --git a/src/shell.c b/src/shell.c
index 6c810ff..35b19a1 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -63,6 +63,12 @@
struct wl_listener seat_destroyed_listener;
};
+struct input_panel_surface {
+ struct wl_list link;
+ struct weston_surface *surface;
+ struct wl_listener listener;
+};
+
struct desktop_shell {
struct weston_compositor *compositor;
@@ -2507,17 +2513,17 @@
{
struct desktop_shell *shell =
container_of(listener, struct desktop_shell, show_input_panel_listener);
- struct weston_surface *surface, *next;
+ struct input_panel_surface *surface, *next;
+ struct weston_surface *ws;
wl_list_for_each_safe(surface, next,
- &shell->input_panel.surfaces, layer_link) {
- wl_list_remove(&surface->layer_link);
+ &shell->input_panel.surfaces, link) {
+ ws = surface->surface;
wl_list_insert(&shell->panel_layer.surface_list,
- &surface->layer_link);
- weston_surface_assign_output(surface);
- weston_surface_damage(surface);
- weston_slide_run(surface,
- surface->geometry.height, 0, NULL, NULL);
+ &ws->layer_link);
+ weston_surface_assign_output(ws);
+ weston_surface_damage(ws);
+ weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
}
}
@@ -2533,11 +2539,8 @@
wl_list_for_each_safe(surface, next,
&shell->panel_layer.surface_list, layer_link)
- if (surface->configure == input_panel_configure) {
+ if (surface->configure == input_panel_configure)
weston_surface_unmap(surface);
- wl_list_insert(&shell->input_panel.surfaces,
- &surface->layer_link);
- }
}
static void
@@ -2898,6 +2901,19 @@
}
static void
+destroy_input_panel_surface(struct wl_listener *listener,
+ void *data)
+{
+ struct input_panel_surface *input_panel_surface =
+ container_of(listener, struct input_panel_surface, listener);
+
+ wl_list_remove(&listener->link);
+ wl_list_remove(&input_panel_surface->link);
+
+ free(input_panel_surface);
+}
+
+static void
input_panel_set_surface(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface_resource,
@@ -2906,11 +2922,26 @@
struct desktop_shell *shell = resource->data;
struct weston_surface *surface = surface_resource->data;
struct weston_output *output = output_resource->data;
+ struct input_panel_surface *input_panel_surface;
surface->configure = input_panel_configure;
surface->private = shell;
surface->output = output;
- wl_list_insert(shell->input_panel.surfaces.prev, &surface->layer_link);
+
+ input_panel_surface = malloc(sizeof *input_panel_surface);
+ if (!input_panel_surface) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ input_panel_surface->surface = surface;
+ input_panel_surface->listener.notify = destroy_input_panel_surface;
+
+ wl_signal_add(&surface_resource->destroy_signal,
+ &input_panel_surface->listener);
+
+ wl_list_insert(&shell->input_panel.surfaces,
+ &input_panel_surface->link);
}
static const struct input_panel_interface input_panel_implementation = {