static const struct wl_data_device_interface data_device_iface;
+static struct ds_data_device *
+data_device_get_or_create(struct ds_data_device_manager *manager,
+ struct ds_seat_client *seat_client);
+static struct ds_data_device *create_data_device(
+ struct ds_data_device_manager *manager,
+ struct ds_seat_client *seat_client);
+static void data_device_destroy(struct ds_data_device *data_device);
static void data_device_handle_resource_destroy(struct wl_resource *resource);
+static void data_device_handle_manager_destroy(struct wl_listener *listener,
+ void *data);
static void data_device_handle_seat_client_destroy(
struct wl_listener *listener, void *data);
static void data_device_handle_seat_set_selection(struct wl_listener *listener,
static void data_device_handle_keyboard_focus_change(
struct wl_listener *listener, void *data);
static void data_device_update_selection(struct ds_data_device *data_device);
+static void data_device_send_selection(struct ds_data_device *data_device,
+ struct wl_resource *resource);
-struct ds_data_device *
-create_data_device(struct ds_data_device_manager *manager,
+void
+create_data_device_resource(struct ds_data_device_manager *manager,
struct wl_client *client, uint32_t version,
uint32_t id, struct wl_resource *seat_resource)
{
struct ds_data_device *data_device;
+ struct ds_seat_client *seat_client, *focused_client;
+ struct wl_resource *resource;
- data_device = calloc(1, sizeof *data_device);
- if (!data_device)
- return NULL;
+ seat_client = ds_seat_client_from_resource(seat_resource);
+ data_device = data_device_get_or_create(manager, seat_client);
+ if (!data_device) {
+ ds_err("Could not create data_device");
+ wl_client_post_no_memory(client);
+ return;
+ }
- data_device->resource = wl_resource_create(client,
- &wl_data_device_interface, version, id);
- if (!data_device->resource) {
+ resource = wl_resource_create(client, &wl_data_device_interface,
+ version, id);
+ if (!resource) {
wl_client_post_no_memory(client);
- return NULL;
+ return;
}
- wl_resource_set_implementation(data_device->resource, &data_device_iface,
+ wl_resource_set_implementation(resource, &data_device_iface,
data_device, data_device_handle_resource_destroy);
+ wl_list_insert(&data_device->resources, wl_resource_get_link(resource));
+
+ focused_client = ds_seat_keyboard_get_focused_client(data_device->seat);
+ if (data_device->seat_client == focused_client)
+ data_device_send_selection(data_device, resource);
+}
+
+static struct ds_data_device *
+data_device_get_or_create(struct ds_data_device_manager *manager,
+ struct ds_seat_client *seat_client)
+{
+ struct ds_data_device *data_device;
+
+ data_device = data_device_for_seat_client(manager, seat_client);
+ if (!data_device)
+ data_device = create_data_device(manager, seat_client);
+
+ return data_device;
+}
+
+static struct ds_data_device *
+create_data_device(struct ds_data_device_manager *manager,
+ struct ds_seat_client *seat_client)
+{
+ struct ds_data_device *data_device;
+
+ data_device = calloc(1, sizeof *data_device);
+ if (!data_device)
+ return NULL;
+
+
+ wl_list_init(&data_device->resources);
+ wl_list_init(&data_device->selection_offers);
+
data_device->manager = manager;
- data_device->seat_client = ds_seat_client_from_resource(seat_resource);
+ data_device->seat_client = seat_client;
data_device->seat = ds_seat_client_get_seat(data_device->seat_client);
+ data_device->manager_destroy.notify = data_device_handle_manager_destroy;
+ wl_signal_add(&manager->events.destroy, &data_device->manager_destroy);
+
data_device->seat_client_destroy.notify =
data_device_handle_seat_client_destroy;
ds_seat_client_add_destroy_listener(data_device->seat_client,
data_device->keyboard_focus_change.notify =
data_device_handle_keyboard_focus_change;
ds_seat_keyboard_add_focus_change_listener(data_device->seat,
- &data_device->keyboard_focus_change);
-
- data_device_update_selection(data_device);
+ &data_device->keyboard_focus_change);
wl_list_insert(&manager->data_devices, &data_device->link);
return data_device;
}
-void
+static void
data_device_destroy(struct ds_data_device *data_device)
{
- wl_list_remove(&data_device->link);
+ struct wl_resource *resource, *resource_tmp;
+ struct ds_data_offer *offer, *offer_tmp;
- if (data_device->seat_client) {
- wl_list_remove(&data_device->seat_client_destroy.link);
- wl_list_remove(&data_device->seat_set_selection.link);
- wl_list_remove(&data_device->keyboard_focus_change.link);
+ wl_list_for_each_safe(offer, offer_tmp, &data_device->selection_offers,
+ link) {
+ data_offer_destroy(offer);
}
- wl_resource_set_user_data(data_device->resource, NULL);
+ wl_resource_for_each_safe(resource, resource_tmp,
+ &data_device->resources) {
+ wl_list_remove(wl_resource_get_link(resource));
+ wl_resource_set_user_data(resource, NULL);
+ }
+ wl_list_remove(&data_device->link);
+ wl_list_remove(&data_device->manager_destroy.link);
+ wl_list_remove(&data_device->seat_client_destroy.link);
+ wl_list_remove(&data_device->seat_set_selection.link);
+ wl_list_remove(&data_device->keyboard_focus_change.link);
free(data_device);
}
if (!data_device)
return;
+ wl_list_remove(wl_resource_get_link(resource));
+ if (!wl_list_empty(&data_device->resources))
+ return;
+
+ data_device_destroy(data_device);
+}
+
+static void data_device_handle_manager_destroy(struct wl_listener *listener,
+ void *data)
+{
+ struct ds_data_device *data_device;
+
+ data_device = wl_container_of(listener, data_device, manager_destroy);
data_device_destroy(data_device);
}
struct ds_data_device *data_device;
data_device = wl_container_of(listener, data_device, seat_client_destroy);
-
- wl_list_remove(&data_device->seat_client_destroy.link);
- wl_list_remove(&data_device->seat_set_selection.link);
- wl_list_remove(&data_device->keyboard_focus_change.link);
-
- data_device->seat_client = NULL;
- data_device->seat = NULL;
+ data_device_destroy(data_device);
}
static void
struct ds_drag *drag;
data_device = wl_resource_get_user_data(resource);
- if (!data_device || !data_device->seat_client)
+ if (!data_device)
return;
if (source_resource) {
struct ds_data_source_client *source = NULL;
data_device = wl_resource_get_user_data(resource);
- if (!data_device || !data_device->seat_client)
+ if (!data_device)
return;
if (source_resource) {
static void
data_device_update_selection(struct ds_data_device *data_device)
{
- struct ds_seat_client *focused_client;
struct ds_data_source *source;
- struct ds_data_offer *offer;
+ struct ds_data_offer *offer, *tmp;
+ struct ds_seat_client *focused_client;
+ struct wl_resource *resource;
+
+ source = ds_seat_get_selection(data_device->seat);
+ if (source)
+ source->accepted = false;
+
+ wl_list_for_each_safe(offer, tmp, &data_device->selection_offers, link)
+ data_offer_destroy(offer);
focused_client = ds_seat_keyboard_get_focused_client(data_device->seat);
- if (data_device->seat_client != focused_client)
- return;
+ if (data_device->seat_client == focused_client) {
+ wl_resource_for_each(resource, &data_device->resources)
+ data_device_send_selection(data_device, resource);
+ }
+}
+
+static void
+data_device_send_selection(struct ds_data_device *data_device,
+ struct wl_resource *device_resource)
+{
+ struct ds_data_source *source;
+ struct ds_data_offer *offer;
source = ds_seat_get_selection(data_device->seat);
if (source) {
- offer = create_data_offer(data_device, source,
+ offer = create_data_offer(device_resource, source,
DS_DATA_OFFER_SELECTION);
if (!offer) {
- wl_resource_post_no_memory(data_device->resource);
+ wl_resource_post_no_memory(device_resource);
return;
}
- wl_data_device_send_selection(data_device->resource, offer->resource);
+ wl_list_insert(&data_device->selection_offers, &offer->link);
+
+ wl_data_device_send_selection(device_resource, offer->resource);
}
else {
- wl_data_device_send_selection(data_device->resource, NULL);
+ wl_data_device_send_selection(device_resource, NULL);
}
}
struct ds_data_device
{
- struct wl_resource *resource;
struct ds_data_device_manager *manager;
struct ds_seat_client *seat_client;
struct ds_seat *seat;
+ struct wl_list resources;
struct wl_list selection_offers; // ds_data_offer.link
struct wl_list link; // ds_data_device_manager.data_devices
+ struct wl_listener manager_destroy;
struct wl_listener seat_client_destroy;
struct wl_listener seat_set_selection;
struct wl_listener keyboard_focus_change;
bool mapped;
};
-struct ds_data_device *create_data_device(
- struct ds_data_device_manager *manager, struct wl_client *client,
- uint32_t version, uint32_t id, struct wl_resource *seat_resource);
+struct ds_data_device *
+data_device_for_seat_client(struct ds_data_device_manager *manager,
+ struct ds_seat_client *seat_client);
-void data_device_destroy(struct ds_data_device *data_device);
+void create_data_device_resource(struct ds_data_device_manager *manager,
+ struct wl_client *client, uint32_t version,
+ uint32_t id, struct wl_resource *seat_resource);
struct ds_data_source_client *create_data_source_client(
struct wl_client *wl_client, uint32_t version, uint32_t id);
struct ds_data_offer *
-create_data_offer(struct ds_data_device *data_device,
+create_data_offer(struct wl_resource *device_resource,
struct ds_data_source *source, enum ds_data_offer_type type);
+void data_offer_destroy(struct ds_data_offer *offer);
+
struct ds_drag *create_drag(struct ds_seat_client *seat_client,
struct ds_data_source *source, struct wl_resource *icon_resource);