From 82d9ee929b50caf27d44f5d0ccfe5497f07015bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 3 Jan 2012 14:11:07 -0500 Subject: [PATCH] data-device: Handle source going away instead of ref-counting it We have to deal with the data source going away. Even if we have a reference to the server side data source, we can't do anything if the client that provided the source went away. So just NULL the offers source pointer in the destroy callback for the source. --- src/compositor.h | 12 +++--- src/data-device.c | 85 ++++++++++++++++++++---------------------- src/xserver-launcher.c | 38 ++----------------- 3 files changed, 52 insertions(+), 83 deletions(-) diff --git a/src/compositor.h b/src/compositor.h index 0f473937..f4530049 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -269,15 +269,17 @@ struct weston_surface { struct wl_listener buffer_destroy_listener; }; +struct weston_data_offer { + struct wl_resource resource; + struct weston_data_source *source; + struct wl_listener source_destroy_listener; +}; + struct weston_data_source { struct wl_resource resource; struct wl_array mime_types; - int refcount; - void *data; - - struct wl_resource *(*create_offer)(struct weston_data_source *source, - struct wl_resource *target); + const struct wl_data_offer_interface *offer_interface; void (*cancel)(struct weston_data_source *source); }; diff --git a/src/data-device.c b/src/data-device.c index 4568a6cc..2072284a 100644 --- a/src/data-device.c +++ b/src/data-device.c @@ -27,36 +27,31 @@ #include "compositor.h" -void -weston_data_source_unref(struct weston_data_source *source) -{ - source->refcount--; - if (source->refcount == 0) - free(source); -} - static void data_offer_accept(struct wl_client *client, struct wl_resource *resource, uint32_t time, const char *mime_type) { - struct weston_data_source *source = resource->data; + struct weston_data_offer *offer = resource->data; /* FIXME: Check that client is currently focused by the input * device that is currently dragging this data source. Should * this be a wl_data_device request? */ - wl_resource_post_event(&source->resource, - WL_DATA_SOURCE_TARGET, mime_type); + if (offer->source) + wl_resource_post_event(&offer->source->resource, + WL_DATA_SOURCE_TARGET, mime_type); } static void data_offer_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct weston_data_source *source = resource->data; + struct weston_data_offer *offer = resource->data; + + if (offer->source) + wl_resource_post_event(&offer->source->resource, + WL_DATA_SOURCE_SEND, mime_type, fd); - wl_resource_post_event(&source->resource, - WL_DATA_SOURCE_SEND, mime_type, fd); close(fd); } @@ -69,10 +64,10 @@ data_offer_destroy(struct wl_client *client, struct wl_resource *resource) static void destroy_data_offer(struct wl_resource *resource) { - struct weston_data_source *source = resource->data; + struct weston_data_offer *offer = resource->data; - weston_data_source_unref(source); - free(resource); + wl_list_remove(&offer->source_destroy_listener.link); + free(offer); } static const struct wl_data_offer_interface data_offer_interface = { @@ -81,18 +76,13 @@ static const struct wl_data_offer_interface data_offer_interface = { data_offer_destroy, }; -static struct wl_resource * -data_source_create_offer(struct weston_data_source *source, - struct wl_resource *target) +static void +destroy_offer_data_source(struct wl_listener *listener, + struct wl_resource *resource, uint32_t time) { - struct wl_resource *resource; - - resource = wl_client_new_object(target->client, - &wl_data_offer_interface, - &data_offer_interface, source); - resource->destroy = destroy_data_offer; + struct weston_data_offer *offer = resource->data; - return resource; + offer->source = NULL; } static void @@ -105,19 +95,36 @@ static struct wl_resource * weston_data_source_send_offer(struct weston_data_source *source, struct wl_resource *target) { - struct wl_resource *resource; + struct weston_data_offer *offer; char **p, **end; - resource = source->create_offer(source, target); - source->refcount++; + offer = malloc(sizeof *offer); + if (offer == NULL) + return NULL; + + offer->resource.destroy = destroy_data_offer; + offer->resource.object.id = 0; + offer->resource.object.interface = &wl_data_offer_interface; + offer->resource.object.implementation = + (void (**)(void)) &source->offer_interface; + offer->resource.data = offer; + + offer->source = source; + offer->source_destroy_listener.func = destroy_offer_data_source; + wl_list_insert(&source->resource.destroy_listener_list, + &offer->source_destroy_listener.link); + + wl_client_add_resource(source->resource.client, &offer->resource); - wl_resource_post_event(target, WL_DATA_DEVICE_DATA_OFFER, resource); + wl_resource_post_event(target, + WL_DATA_DEVICE_DATA_OFFER, &offer->resource); end = source->mime_types.data + source->mime_types.size; for (p = source->mime_types.data; p < end; p++) - wl_resource_post_event(resource, WL_DATA_OFFER_OFFER, *p); + wl_resource_post_event(&offer->resource, + WL_DATA_OFFER_OFFER, *p); - return resource; + return &offer->resource; } static void @@ -240,7 +247,6 @@ drag_grab_end(struct wl_grab *grab, uint32_t time) WL_DATA_DEVICE_DROP); drag_set_focus(device, NULL, time, 0, 0); - weston_data_source_unref(device->drag_data_source); device->drag_data_source = NULL; } @@ -271,7 +277,6 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource, device->grab.interface = &drag_grab_interface; device->drag_data_source = source_resource->data; - device->drag_data_source->refcount++; target = pick_surface(&device->input_device, &sx, &sy); wl_input_device_set_pointer_focus(&device->input_device, @@ -314,17 +319,11 @@ weston_input_device_set_selection(struct weston_input_device *device, if (device->selection_data_source) { device->selection_data_source->cancel(device->selection_data_source); - /* FIXME: All non-active clients will probably hold a - * reference to the selection data source, and thus it - * won't get destroyed until every client has been - * activated and seen the new selection event. */ wl_list_remove(&device->selection_data_source_listener.link); - weston_data_source_unref(device->selection_data_source); device->selection_data_source = NULL; } device->selection_data_source = source; - source->refcount++; focus = device->input_device.keyboard_focus_resource; if (focus) { @@ -379,7 +378,6 @@ destroy_data_source(struct wl_resource *resource) wl_array_release(&source->mime_types); source->resource.object.id = 0; - weston_data_source_unref(source); } static void @@ -400,9 +398,8 @@ create_data_source(struct wl_client *client, source->resource.object.implementation = (void (**)(void)) &data_source_interface; source->resource.data = source; - source->create_offer = data_source_create_offer; + source->offer_interface = &data_offer_interface; source->cancel = data_source_cancel; - source->refcount = 1; wl_array_init(&source->mime_types); wl_client_add_resource(client, &source->resource); diff --git a/src/xserver-launcher.c b/src/xserver-launcher.c index 4f33ef73..85e22134 100644 --- a/src/xserver-launcher.c +++ b/src/xserver-launcher.c @@ -237,18 +237,13 @@ static void data_offer_accept(struct wl_client *client, struct wl_resource *resource, uint32_t time, const char *mime_type) { - struct weston_data_source *source = resource->data; - - wl_resource_post_event(&source->resource, - WL_DATA_SOURCE_TARGET, mime_type); } static void data_offer_receive(struct wl_client *client, struct wl_resource *resource, const char *mime_type, int32_t fd) { - struct weston_data_source *source = resource->data; - struct weston_wm *wm = source->data; + struct weston_wm *wm = resource->data; if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) { /* Get data for the utf8_string target */ @@ -274,35 +269,12 @@ data_offer_destroy(struct wl_client *client, struct wl_resource *resource) wl_resource_destroy(resource, weston_compositor_get_time()); } -static void -destroy_data_offer(struct wl_resource *resource) -{ - struct weston_data_source *source = resource->data; - - weston_data_source_unref(source); - free(resource); -} - static const struct wl_data_offer_interface data_offer_interface = { data_offer_accept, data_offer_receive, data_offer_destroy, }; -static struct wl_resource * -data_source_create_offer(struct weston_data_source *source, - struct wl_resource *target) -{ - struct wl_resource *resource; - - resource = wl_client_new_object(target->client, - &wl_data_offer_interface, - &data_offer_interface, source); - resource->destroy = destroy_data_offer; - - return resource; -} - static void data_source_cancel(struct weston_data_source *source) { @@ -341,10 +313,9 @@ weston_wm_get_selection_targets(struct weston_wm *wm) return; wl_list_init(&source->resource.destroy_listener_list); - source->create_offer = data_source_create_offer; + source->offer_interface = &data_offer_interface; source->cancel = data_source_cancel; - source->data = wm; - source->refcount = 1; + source->resource.data = wm; wl_array_init(&source->mime_types); value = xcb_get_property_value(reply); @@ -361,7 +332,6 @@ weston_wm_get_selection_targets(struct weston_wm *wm) weston_input_device_set_selection(device, source, weston_compositor_get_time()); - weston_data_source_unref(source); free(reply); } @@ -500,7 +470,7 @@ weston_xserver_set_selection(struct weston_input_device *device) } if (wm && has_text_plain && - source->create_offer != data_source_create_offer) { + source->offer_interface != &data_offer_interface) { xcb_set_selection_owner(wm->conn, wm->selection_window, wm->atom.clipboard,