Track client objects and destroy them on disconnect.
authorKristian Høgsberg <krh@redhat.com>
Sun, 12 Oct 2008 01:37:55 +0000 (21:37 -0400)
committerKristian Høgsberg <krh@redhat.com>
Thu, 6 Nov 2008 15:51:58 +0000 (10:51 -0500)
We're going to need a virtual destructor eventually...

wayland.c

index 20fbcb8..398f637 100644 (file)
--- a/wayland.c
+++ b/wayland.c
 
 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
 
+#define container_of(ptr, type, member) ({                     \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
 struct wl_list {
        struct wl_list *prev;
        struct wl_list *next;
@@ -45,6 +50,7 @@ struct wl_client {
        struct wl_connection *connection;
        struct wl_event_source *source;
        struct wl_display *display;
+       struct wl_list object_list;
 };
 
 struct wl_display {
@@ -78,6 +84,10 @@ struct wl_surface {
        void *compositor_data;
 };
 
+struct wl_object_ref {
+       struct wl_object *object;
+       struct wl_list link;
+};
                                   
 static void
 wl_surface_destroy(struct wl_client *client,
@@ -279,6 +289,7 @@ wl_client_event(struct wl_client *client, struct wl_object *object, uint32_t eve
 
 #define WL_DISPLAY_INVALID_OBJECT 0
 #define WL_DISPLAY_INVALID_METHOD 1
+#define WL_DISPLAY_NO_MEMORY 2
 
 static void
 wl_client_connection_data(int fd, uint32_t mask, void *data)
@@ -383,6 +394,7 @@ wl_client_create(struct wl_display *display, int fd)
        client->connection = wl_connection_create(fd,
                                                  wl_client_connection_update, 
                                                  client);
+       wl_list_init(&client->object_list);
 
        wl_connection_write(client->connection,
                            &display->client_id_range,
@@ -397,7 +409,18 @@ wl_client_create(struct wl_display *display, int fd)
 void
 wl_client_destroy(struct wl_client *client)
 {
+       struct wl_object_ref *ref;
+
        printf("disconnect from client %p\n", client);
+
+       while (client->object_list.next != &client->object_list) {
+               ref = container_of(client->object_list.next,
+                                  struct wl_object_ref, link);
+               wl_list_remove(&ref->link);
+               wl_surface_destroy(client, (struct wl_surface *) ref->object);
+               free(ref);
+       }
+
        wl_event_loop_remove_source(client->display->loop, client->source);
        wl_connection_destroy(client->connection);
        free(client);
@@ -408,11 +431,20 @@ wl_display_create_surface(struct wl_client *client,
                          struct wl_display *display, uint32_t id)
 {
        struct wl_surface *surface;
+       struct wl_object_ref *ref;
 
        surface = wl_surface_create(display, id);
-       wl_hash_insert(&display->objects, &surface->base);
 
-       /* FIXME: garbage collect client resources when client exits. */
+       ref = malloc(sizeof *ref);
+       if (ref == NULL) {
+               wl_client_event(client, &display->base,
+                               WL_DISPLAY_NO_MEMORY);
+               return -1;
+       }
+
+       ref->object = &surface->base;
+       wl_hash_insert(&display->objects, &surface->base);
+       wl_list_insert(client->object_list.prev, &ref->link);
 
        return 0;
 }
@@ -532,10 +564,6 @@ wl_display_add_socket(struct wl_display *display)
 }
 
 
-#define container_of(ptr, type, member) ({                     \
-       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-       (type *)( (char *)__mptr - offsetof(type,member) );})
-
 struct wl_surface_iterator {
        struct wl_list *head;
        struct wl_surface *surface;