#include <stdlib.h>
+#include "libds/log.h"
#include "data_device_private.h"
static const struct wl_data_device_interface data_device_iface;
uint32_t serial)
{
struct ds_data_device *data_device;
+ struct ds_data_source_client *source_client = NULL;
+ struct ds_data_source *source = NULL;
+ struct ds_drag *drag;
data_device = wl_resource_get_user_data(resource);
- if (!data_device)
+ if (!data_device || !data_device->seat_client)
+ return;
+
+ if (source_resource) {
+ source_client = wl_resource_get_user_data(source_resource);
+ source = &source_client->base;
+ }
+
+ drag = create_drag(data_device->seat_client, source, icon_resource);
+ if (!drag) {
+ ds_err("Could not create ds_drag");
+ wl_resource_post_no_memory(resource);
return;
+ }
+
+ if (source_client)
+ source_client->finalized = true;
- // TODO
+ struct ds_event_request_start_drag event = {
+ .seat = data_device->seat,
+ .drag = drag,
+ .origin = ds_surface_from_resource(origin_resource),
+ .serial = serial,
+ };
+ wl_signal_emit(&data_device->manager->events.request_start_drag, &event);
}
static void
struct {
struct wl_signal destroy;
struct wl_signal request_set_selection;
+ struct wl_signal request_start_drag;
struct wl_signal request_data_offer_receive;
} events;
};
struct wl_listener source_destroy;
};
+struct ds_drag_icon;
+
+struct ds_drag
+{
+ struct ds_seat_keyboard_grab keyboard_grab;
+ struct ds_seat_pointer_grab pointer_grab;
+ struct ds_seat_touch_grab touch_grab;
+
+ struct ds_seat *seat;
+ struct ds_seat_client *seat_client;
+ struct ds_seat_client *focused_client;
+
+ struct ds_drag_icon *icon;
+ struct ds_data_source *source;
+
+ struct wl_listener icon_destroy;
+ struct wl_listener source_destroy;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+};
+
+struct ds_drag_icon
+{
+ struct ds_drag *drag;
+ struct ds_surface *surface;
+
+ struct wl_listener surface_destroy;
+
+ struct {
+ struct wl_signal destroy;
+ struct wl_signal map;
+ struct wl_signal unmap;
+ } events;
+
+ 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);
create_data_offer(struct ds_data_device *data_device,
struct ds_data_source *source, enum ds_data_offer_type type);
+struct ds_drag *create_drag(struct ds_seat_client *seat_client,
+ struct ds_data_source *source, struct wl_resource *icon_resource);
+
#endif
--- /dev/null
+#include <stdlib.h>
+#include "data_device_private.h"
+
+static void drag_destroy(struct ds_drag *drag);
+static struct ds_drag_icon *create_drag_icon(struct ds_drag *drag,
+ struct wl_resource *icon_resource);
+static void drag_handle_icon_destroy(struct wl_listener *listener, void *data);
+static void drag_handle_source_destroy(struct wl_listener *listener,
+ void *data);
+static void drag_icon_destroy(struct ds_drag_icon *icon);
+
+WL_EXPORT void
+ds_drag_destroy(struct ds_drag *drag)
+{
+ drag_destroy(drag);
+}
+
+struct ds_drag *
+create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source,
+ struct wl_resource *icon_resource)
+{
+ struct ds_drag *drag;
+
+ drag = calloc(1, sizeof *drag);
+ if (!drag)
+ return NULL;
+
+ drag->seat = ds_seat_client_get_seat(seat_client);
+ drag->seat_client = seat_client;
+
+ // FIXME ds_seat_client_add_destroy_listener()?
+
+ if (icon_resource) {
+ drag->icon = create_drag_icon(drag, icon_resource);
+ if (!drag->icon) {
+ free(drag);
+ return NULL;
+ }
+
+ drag->icon_destroy.notify = drag_handle_icon_destroy;
+ wl_signal_add(&drag->icon->events.destroy, &drag->icon_destroy);
+ }
+
+ if (source) {
+ drag->source = source;
+
+ drag->source_destroy.notify = drag_handle_source_destroy;
+ wl_signal_add(&source->events.destroy, &drag->source_destroy);
+ }
+
+ // TODO Add grab interface
+
+ return drag;
+}
+
+static void
+drag_destroy(struct ds_drag *drag)
+{
+ wl_signal_emit(&drag->events.destroy, drag);
+
+ if (drag->source)
+ wl_list_remove(&drag->source_destroy.link);
+
+ if (drag->icon) {
+ wl_list_remove(&drag->icon_destroy.link);
+ drag_icon_destroy(drag->icon);
+ }
+
+ free(drag);
+}
+
+static void
+drag_handle_icon_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_drag *drag;
+
+ drag = wl_container_of(listener, drag, icon_destroy);
+ drag->icon = NULL;
+}
+
+static void
+drag_handle_source_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_drag *drag;
+
+ drag = wl_container_of(listener, drag, source_destroy);
+ drag_destroy(drag);
+}
+
+const struct ds_surface_role drag_icon_surface_role;
+
+static void drag_icon_handle_surface_destroy(struct wl_listener *listener,
+ void *data);
+static void drag_icon_set_mapped(struct ds_drag_icon *icon, bool mapped);
+
+static struct ds_drag_icon *
+create_drag_icon(struct ds_drag *drag, struct wl_resource *icon_resource)
+{
+ struct ds_drag_icon *icon;
+
+ icon = calloc(1, sizeof *icon);
+ if (!icon)
+ return NULL;
+
+ icon->drag = drag;
+
+ wl_signal_init(&icon->events.destroy);
+ wl_signal_init(&icon->events.map);
+ wl_signal_init(&icon->events.unmap);
+
+ icon->surface = ds_surface_from_resource(icon_resource);
+ if (!ds_surface_set_role(icon->surface, &drag_icon_surface_role, icon,
+ icon_resource, WL_DATA_DEVICE_ERROR_ROLE)) {
+ free(icon);
+ return NULL;
+ }
+
+ icon->surface_destroy.notify = drag_icon_handle_surface_destroy;
+ ds_surface_add_destroy_listener(icon->surface, &icon->surface_destroy);
+
+ if (ds_surface_has_buffer(icon->surface))
+ drag_icon_set_mapped(icon, true);
+
+ return icon;
+}
+
+static void
+drag_icon_destroy(struct ds_drag_icon *icon)
+{
+ drag_icon_set_mapped(icon, false);
+ wl_signal_emit(&icon->events.destroy, icon);
+ wl_list_remove(&icon->surface_destroy.link);
+ ds_surface_reset_role_data(icon->surface);
+ free(icon);
+}
+
+static void drag_icon_set_mapped(struct ds_drag_icon *icon, bool mapped)
+{
+ if (mapped && !icon->mapped) {
+ icon->mapped = true;
+ wl_signal_emit(&icon->events.map, icon);
+ }
+ else if (!mapped && icon->mapped) {
+ wl_signal_emit(&icon->events.unmap, icon);
+ icon->mapped = false;
+ }
+}
+
+static void
+drag_icon_surface_role_commit(struct ds_surface *surface)
+{
+ struct ds_drag_icon *icon;
+
+ icon = ds_surface_get_role_data(surface);
+ if (!icon)
+ return;
+
+ drag_icon_set_mapped(icon, ds_surface_has_buffer(surface));
+}
+
+const struct ds_surface_role drag_icon_surface_role = {
+ .name = "wl_data_device-icon",
+ .commit = drag_icon_surface_role_commit,
+};
+
+static void
+drag_icon_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_drag_icon *icon;
+
+ icon = wl_container_of(listener, icon, surface_destroy);
+ drag_icon_destroy(icon);
+}