diff options
author | Rob Bradford <rob@linux.intel.com> | 2013-04-03 15:20:49 +0100 |
---|---|---|
committer | Kristian Høgsberg <krh@bitplanet.net> | 2013-04-03 12:46:57 -0400 |
commit | db19b443cc8d3179df31cb96b9c45527ad403fef (patch) | |
tree | 84bb0e6583dd2c9c633176b910dc6bf9fca42e0e | |
parent | 858fcbde59cfd2b42644c43bf481ffd70b30d5be (diff) |
wayland-server: Listen for pointer current surface destruction
Add a destroy listener so that when the current surface associated with the
pointer is destroyed we can reset the pointer to the current surface. In order
to achieve this add a wl_pointer_set_current() which handles assigning the
surface and creating the listener.
This resolves a use-after-free error triggered with nested popup surfaces
Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=696946
-rw-r--r-- | src/wayland-server.c | 25 | ||||
-rw-r--r-- | src/wayland-server.h | 3 |
2 files changed, 28 insertions, 0 deletions
diff --git a/src/wayland-server.c b/src/wayland-server.c index 384b465..2109674 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -946,6 +946,31 @@ wl_pointer_end_grab(struct wl_pointer *pointer) pointer->current_x, pointer->current_y); } +static void +current_surface_destroy(struct wl_listener *listener, void *data) +{ + struct wl_pointer *pointer = + container_of(listener, struct wl_pointer, current_listener); + + pointer->current = NULL; +} + +WL_EXPORT void +wl_pointer_set_current(struct wl_pointer *pointer, struct wl_surface *surface) +{ + if (pointer->current) + wl_list_remove(&pointer->current_listener.link); + + pointer->current = surface; + + if (!surface) + return; + + wl_signal_add(&surface->resource.destroy_signal, + &pointer->current_listener); + pointer->current_listener.notify = current_surface_destroy; +} + WL_EXPORT void wl_touch_start_grab(struct wl_touch *touch, struct wl_touch_grab *grab) { diff --git a/src/wayland-server.h b/src/wayland-server.h index e5a862a..af2be62 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -312,6 +312,7 @@ struct wl_pointer { wl_fixed_t x, y; struct wl_surface *current; + struct wl_listener current_listener; wl_fixed_t current_x, current_y; uint32_t button_count; @@ -450,6 +451,8 @@ wl_pointer_start_grab(struct wl_pointer *pointer, struct wl_pointer_grab *grab); void wl_pointer_end_grab(struct wl_pointer *pointer); +void +wl_pointer_set_current(struct wl_pointer *pointer, struct wl_surface *surface); void wl_keyboard_init(struct wl_keyboard *keyboard); |