diff options
author | Kristian Høgsberg <krh@redhat.com> | 2009-03-10 23:17:00 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2009-03-10 23:43:23 -0400 |
commit | 4fa4873928f2903dc4aeebf63236aa151b504c03 (patch) | |
tree | 071d8aa4088d6ebe45fca55e23041fdb8863086d | |
parent | 786ca0d572bc38e32f5b79cf4971752babd0b245 (diff) | |
download | wayland-4fa4873928f2903dc4aeebf63236aa151b504c03.tar.gz wayland-4fa4873928f2903dc4aeebf63236aa151b504c03.tar.xz wayland-4fa4873928f2903dc4aeebf63236aa151b504c03.zip |
Dont crash when surfaces and clients disappear
Set up a notification system, so we get a callback when a client and its
surfaces disappear and can drop references the lost surface.
-rw-r--r-- | wayland-system-compositor.c | 58 |
1 files changed, 51 insertions, 7 deletions
diff --git a/wayland-system-compositor.c b/wayland-system-compositor.c index 1a28f76..719426f 100644 --- a/wayland-system-compositor.c +++ b/wayland-system-compositor.c @@ -63,6 +63,14 @@ struct wl_visual { struct wl_object base; }; +struct wlsc_surface; + +struct wlsc_listener { + struct wl_list link; + void (*func)(struct wlsc_listener *listener, + struct wlsc_surface *surface); +}; + struct wlsc_output { struct wl_object base; struct wl_list link; @@ -89,6 +97,8 @@ struct wlsc_input_device { struct wlsc_surface *pointer_focus; struct wlsc_surface *keyboard_focus; struct wl_array keys; + + struct wlsc_listener listener; }; struct wlsc_compositor { @@ -104,6 +114,8 @@ struct wlsc_compositor { struct wl_list input_device_list; struct wl_list surface_list; + struct wl_list surface_destroy_listener_list; + struct wl_event_source *term_signal_source; /* tty handling state */ @@ -386,12 +398,25 @@ wlsc_surface_create_from_cairo_surface(struct wlsc_compositor *ec, } static void -wlsc_surface_destroy(struct wlsc_surface *es, struct wlsc_compositor *ec) +wlsc_surface_destroy(struct wlsc_surface *surface, + struct wlsc_compositor *compositor) { - glDeleteTextures(1, &es->texture); - if (es->surface != EGL_NO_SURFACE) - eglDestroySurface(ec->display, es->surface); - free(es); + struct wlsc_listener *l; + + l = container_of(compositor->surface_destroy_listener_list.next, + struct wlsc_listener, link); + while (&l->link != &compositor->surface_destroy_listener_list) { + l->func(l, surface); + l = container_of(l->link.next, struct wlsc_listener, link); + } + + wl_list_remove(&surface->link); + wl_list_remove(&surface->animate.link); + + glDeleteTextures(1, &surface->texture); + if (surface->surface != EGL_NO_SURFACE) + eglDestroySurface(compositor->display, surface->surface); + free(surface); } static void @@ -674,8 +699,6 @@ surface_destroy(struct wl_client *client, struct wlsc_surface *es = (struct wlsc_surface *) surface; struct wlsc_compositor *ec = es->compositor; - wl_list_remove(&es->link); - wl_list_remove(&es->animate.link); wlsc_surface_destroy(es, ec); schedule_repaint(ec); @@ -1108,6 +1131,23 @@ struct evdev_input_device * evdev_input_device_create(struct wlsc_input_device *device, struct wl_display *display, const char *path); +static void +handle_surface_destroy(struct wlsc_listener *listener, + struct wlsc_surface *surface) +{ + struct wlsc_input_device *device = + container_of(listener, struct wlsc_input_device, listener); + + if (device->grab_surface == surface) { + device->grab_surface = NULL; + device->grab = 0; + } + if (device->keyboard_focus == surface) + device->keyboard_focus = NULL; + if (device->pointer_focus == surface) + device->pointer_focus = NULL; +} + static struct wlsc_input_device * create_input_device(struct wlsc_compositor *ec) { @@ -1126,6 +1166,9 @@ create_input_device(struct wlsc_compositor *ec) device->y = 100; device->ec = ec; + device->listener.func = handle_surface_destroy; + wl_list_insert(ec->surface_destroy_listener_list.prev, + &device->listener.link); wl_list_insert(ec->input_device_list.prev, &device->link); return device; @@ -1506,6 +1549,7 @@ wlsc_compositor_create(struct wl_display *display) wl_list_init(&ec->surface_list); wl_list_init(&ec->input_device_list); wl_list_init(&ec->output_list); + wl_list_init(&ec->surface_destroy_listener_list); if (init_libudev(ec) < 0) { fprintf(stderr, "failed to initialize devices\n"); return NULL; |