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.
dev
Kristian Høgsberg 13 years ago
parent cb78447a0e
commit 82d9ee929b
  1. 12
      src/compositor.h
  2. 81
      src/data-device.c
  3. 38
      src/xserver-launcher.c

@ -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);
};

@ -27,25 +27,18 @@
#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,
if (offer->source)
wl_resource_post_event(&offer->source->resource,
WL_DATA_SOURCE_TARGET, mime_type);
}
@ -53,10 +46,12 @@ 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;
wl_resource_post_event(&source->resource,
if (offer->source)
wl_resource_post_event(&offer->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);

@ -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,

Loading…
Cancel
Save