[PATCH weston 5/5] Port to new drag & drop interface
Daniel Stone
daniel at fooishbar.org
Mon Jul 23 11:55:01 PDT 2012
Track the changes to the drag & drop protocol, in particular splitting
wl_drag_offer and wl_selection_offer out of the singleton management
protocol. Note that we can potentially have multiple drags active at
once, although not all clients allow for this right now.
This also removes dnd's self_only option, as it's difficult (or nigh
on impossible) to support with multiple active drags.
Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
clients/dnd.c | 208 +++++++--------
clients/terminal.c | 6 +-
clients/window.c | 648 ++++++++++++++++++++++++++++++----------------
clients/window.h | 63 ++++-
src/clipboard.c | 18 +-
src/compositor.c | 34 +--
src/xwayland/selection.c | 12 +-
7 files changed, 598 insertions(+), 391 deletions(-)
diff --git a/clients/dnd.c b/clients/dnd.c
index c38b94f..ce99adf 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -45,17 +45,17 @@ struct dnd {
struct display *display;
uint32_t key;
struct item *items[16];
- int self_only;
- struct dnd_drag *current_drag;
+ struct wl_list drag_list;
};
struct dnd_drag {
+ struct dnd *dnd;
+ struct input *input;
+ struct wl_list link;
+
cairo_surface_t *translucent;
cairo_surface_t *opaque;
int hotspot_x, hotspot_y;
- struct dnd *dnd;
- struct input *input;
- uint32_t time;
struct item *item;
int x_offset, y_offset;
int width, height;
@@ -90,7 +90,6 @@ item_create(struct display *display, int x, int y, int seed)
if (item == NULL)
return NULL;
-
gettimeofday(&tv, NULL);
item->seed = seed ? seed : tv.tv_usec;
srandom(item->seed);
@@ -220,6 +219,7 @@ dnd_add_item(struct dnd *dnd, struct item *item)
return i;
}
}
+
return -1;
}
@@ -247,8 +247,8 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
}
static void
-data_source_target(void *data,
- struct wl_data_source *source, const char *mime_type)
+data_source_accepted(void *data, struct wl_data_source *source,
+ const char *mime_type)
{
struct dnd_drag *dnd_drag = data;
struct dnd *dnd = dnd_drag->dnd;
@@ -268,12 +268,12 @@ data_source_target(void *data,
}
static void
-data_source_send(void *data, struct wl_data_source *source,
- const char *mime_type, int32_t fd)
+data_source_transfer(void *data, struct wl_data_source *source,
+ const char *mime_type, int32_t fd)
{
- struct dnd_flower_message dnd_flower_message;
+ struct dnd_flower_message dnd_flower_message;
struct dnd_drag *dnd_drag = data;
-
+
dnd_flower_message.seed = dnd_drag->item->seed;
dnd_flower_message.x_offset = dnd_drag->x_offset;
dnd_flower_message.y_offset = dnd_drag->y_offset;
@@ -285,7 +285,7 @@ data_source_send(void *data, struct wl_data_source *source,
}
static void
-data_source_cancelled(void *data, struct wl_data_source *source)
+data_source_inactive(void *data, struct wl_data_source *source)
{
struct dnd_drag *dnd_drag = data;
@@ -294,7 +294,7 @@ data_source_cancelled(void *data, struct wl_data_source *source)
* up the drag object created and the local state. */
wl_data_source_destroy(dnd_drag->data_source);
-
+
/* Destroy the item that has been dragged out */
cairo_surface_destroy(dnd_drag->item->surface);
free(dnd_drag->item);
@@ -307,9 +307,9 @@ data_source_cancelled(void *data, struct wl_data_source *source)
}
static const struct wl_data_source_listener data_source_listener = {
- data_source_target,
- data_source_send,
- data_source_cancelled
+ data_source_accepted,
+ data_source_transfer,
+ data_source_inactive
};
static cairo_surface_t *
@@ -379,71 +379,57 @@ dnd_button_handler(struct widget *widget,
x -= allocation.x;
y -= allocation.y;
- if (item && state == WL_POINTER_BUTTON_STATE_PRESSED) {
- dnd_drag = malloc(sizeof *dnd_drag);
- dnd_drag->dnd = dnd;
- dnd_drag->input = input;
- dnd_drag->time = time;
- dnd_drag->item = item;
- dnd_drag->x_offset = x - item->x;
- dnd_drag->y_offset = y - item->y;
-
- for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
- if (item == dnd->items[i]){
- dnd->items[i] = 0;
- break;
- }
- }
-
- display = window_get_display(dnd->window);
- compositor = display_get_compositor(display);
- serial = display_get_serial(display);
- dnd_drag->drag_surface =
- wl_compositor_create_surface(compositor);
-
- input_ungrab(input);
-
- if (dnd->self_only) {
- dnd_drag->data_source = NULL;
- } else {
- dnd_drag->data_source =
- display_create_data_source(dnd->display);
- wl_data_source_add_listener(dnd_drag->data_source,
- &data_source_listener,
- dnd_drag);
- wl_data_source_offer(dnd_drag->data_source,
- "application/x-wayland-dnd-flower");
- wl_data_source_offer(dnd_drag->data_source,
- "text/plain; charset=utf-8");
- }
-
- wl_data_device_start_drag(input_get_data_device(input),
- dnd_drag->data_source,
- window_get_wl_surface(dnd->window),
- dnd_drag->drag_surface,
- serial);
-
- input_set_pointer_image(input, CURSOR_DRAGGING);
+ if (!item || state != WL_POINTER_BUTTON_STATE_PRESSED)
+ return;
- dnd_drag->opaque =
- create_drag_cursor(dnd_drag, item, x, y, 1);
- dnd_drag->translucent =
- create_drag_cursor(dnd_drag, item, x, y, 0.2);
+ dnd_drag = malloc(sizeof *dnd_drag);
+ dnd_drag->dnd = dnd;
+ dnd_drag->input = input;
+ dnd_drag->item = item;
+ dnd_drag->x_offset = x - item->x;
+ dnd_drag->y_offset = y - item->y;
+ wl_list_init(&dnd_drag->link);
- if (dnd->self_only)
- icon = dnd_drag->opaque;
- else
- icon = dnd_drag->translucent;
+ for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
+ if (item != dnd->items[i])
+ continue;
+ dnd->items[i] = 0;
+ break;
+ }
- buffer = display_get_buffer_for_surface(dnd->display, icon);
- wl_surface_attach(dnd_drag->drag_surface, buffer,
- -dnd_drag->hotspot_x, -dnd_drag->hotspot_y);
- wl_surface_damage(dnd_drag->drag_surface, 0, 0,
- dnd_drag->width, dnd_drag->height);
+ display = window_get_display(dnd->window);
+ compositor = display_get_compositor(display);
+ serial = display_get_serial(display);
+ dnd_drag->drag_surface =
+ wl_compositor_create_surface(compositor);
+
+ dnd_drag->opaque =
+ create_drag_cursor(dnd_drag, item, x, y, 1);
+ dnd_drag->translucent =
+ create_drag_cursor(dnd_drag, item, x, y, 0.2);
+
+ icon = dnd_drag->translucent;
+ dnd_drag->data_source = input_create_data_source(input);
+ wl_data_source_add_listener(dnd_drag->data_source,
+ &data_source_listener,
+ dnd_drag);
+ wl_data_source_add_type(dnd_drag->data_source,
+ "application/x-wayland-dnd-flower");
+ wl_data_source_add_type(dnd_drag->data_source,
+ "text/plain; charset=utf-8");
+
+ wl_list_insert(&dnd->drag_list, &dnd_drag->link);
+ input_ungrab(input);
+ input_begin_drag(input, dnd_drag->data_source, dnd->window,
+ dnd_drag->drag_surface, serial);
+
+ buffer = display_get_buffer_for_surface(dnd->display, icon);
+ wl_surface_attach(dnd_drag->drag_surface, buffer,
+ -dnd_drag->hotspot_x, -dnd_drag->hotspot_y);
+ wl_surface_damage(dnd_drag->drag_surface, 0, 0,
+ dnd_drag->width, dnd_drag->height);
- dnd->current_drag = dnd_drag;
- window_schedule_redraw(dnd->window);
- }
+ window_schedule_redraw(dnd->window);
}
static int
@@ -464,8 +450,6 @@ dnd_enter_handler(struct widget *widget,
{
struct dnd *dnd = data;
- dnd->current_drag = NULL;
-
return lookup_cursor(dnd, x, y);
}
@@ -477,21 +461,22 @@ dnd_motion_handler(struct widget *widget,
return lookup_cursor(data, x, y);
}
-static void
-dnd_data_handler(struct window *window,
- struct input *input,
- float x, float y, const char **types, void *data)
+static void *
+dnd_drag_enter_handler(struct window *window, struct drag_offer *drag_offer,
+ float x, float y, struct wl_array *types, void *data)
{
struct dnd *dnd = data;
+ const char *type = *((const char **) types->data);
- if (!types)
- return;
+ input_accept_drag(drag_offer, type);
- if (dnd_get_item(dnd, x, y) || dnd->self_only) {
- input_accept(input, NULL);
- } else {
- input_accept(input, types[0]);
- }
+ return window;
+}
+
+static void
+dnd_drag_motion_handler(struct window *window, struct drag_offer *drag_offer,
+ float x, float y, void *data)
+{
}
static void
@@ -509,7 +494,7 @@ dnd_receive_func(void *data, size_t len, int32_t x, int32_t y, void *user_data)
len, sizeof *message);
return;
}
-
+
widget_get_allocation(dnd->widget, &allocation);
item = item_create(dnd->display,
x - message->x_offset - allocation.x,
@@ -521,30 +506,24 @@ dnd_receive_func(void *data, size_t len, int32_t x, int32_t y, void *user_data)
}
static void
-dnd_drop_handler(struct window *window, struct input *input,
- int32_t x, int32_t y, void *data)
+dnd_drop_handler(struct window *window, struct drag_offer *drag_offer,
+ float x, float y, void *data)
{
struct dnd *dnd = data;
struct dnd_flower_message message;
- if (dnd_get_item(dnd, x, y)) {
- fprintf(stderr, "got 'drop', but no target\n");
+ if (dnd_get_item(dnd, x, y))
return;
- }
- if (!dnd->self_only) {
- input_receive_drag_data(input,
- "application/x-wayland-dnd-flower",
- dnd_receive_func, dnd);
- } else if (dnd->current_drag) {
- message.seed = dnd->current_drag->item->seed;
- message.x_offset = dnd->current_drag->x_offset;
- message.y_offset = dnd->current_drag->y_offset;
- dnd_receive_func(&message, sizeof message, x, y, dnd);
- dnd->current_drag = NULL;
- } else {
- fprintf(stderr, "ignoring drop from another client\n");
- }
+ input_receive_drag_data(drag_offer,
+ "application/x-wayland-dnd-flower",
+ dnd_receive_func, dnd);
+}
+
+static void
+dnd_drag_leave_handler(struct window *window, struct drag_offer *drag_offer,
+ void *data)
+{
}
static struct dnd *
@@ -560,6 +539,7 @@ dnd_create(struct display *display)
return dnd;
memset(dnd, 0, sizeof *dnd);
+ wl_list_init(&dnd->drag_list);
dnd->window = window_create(display);
dnd->widget = frame_create(dnd->window, dnd);
window_set_title(dnd->window, "Wayland Drag and Drop Demo");
@@ -579,8 +559,10 @@ dnd_create(struct display *display)
window_set_user_data(dnd->window, dnd);
window_set_keyboard_focus_handler(dnd->window,
keyboard_focus_handler);
- window_set_data_handler(dnd->window, dnd_data_handler);
+ window_set_drag_enter_handler(dnd->window, dnd_drag_enter_handler);
+ window_set_drag_motion_handler(dnd->window, dnd_drag_motion_handler);
window_set_drop_handler(dnd->window, dnd_drop_handler);
+ window_set_drag_leave_handler(dnd->window, dnd_drag_leave_handler);
widget_set_redraw_handler(dnd->widget, dnd_redraw_handler);
widget_set_enter_handler(dnd->widget, dnd_enter_handler);
@@ -610,10 +592,6 @@ main(int argc, char *argv[])
dnd = dnd_create(d);
- for (i = 1; i < argc; i++)
- if (strcmp("--self-only", argv[i]) == 0)
- dnd->self_only = 1;
-
display_run(d);
return 0;
diff --git a/clients/terminal.c b/clients/terminal.c
index a726232..3cd35b0 100644
--- a/clients/terminal.c
+++ b/clients/terminal.c
@@ -2079,9 +2079,9 @@ handle_bound_key(struct terminal *terminal,
* through to copy. */
case XKB_KEY_C:
terminal->selection =
- display_create_data_source(terminal->display);
- wl_data_source_offer(terminal->selection,
- "text/plain;charset=utf-8");
+ input_create_data_source(input);
+ wl_data_source_add_type(terminal->selection,
+ "text/plain;charset=utf-8");
wl_data_source_add_listener(terminal->selection,
&data_source_listener, terminal);
input_set_selection(input, terminal->selection,
diff --git a/clients/window.c b/clients/window.c
index 2a7010a..9e2a612 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -67,13 +67,51 @@
#include "window.h"
struct shm_pool;
+struct input;
+
+struct data_transfer {
+ struct task io_task;
+ struct input *input;
+ int fd;
+ data_func_t func;
+ int32_t x, y;
+ void *user_data;
+ void (*unref)(struct data_transfer *transfer);
+};
+
+struct selection_offer {
+ struct wl_selection_offer *offer;
+ struct input *input;
+ struct wl_array types;
+ int refcount;
+
+ struct data_transfer transfer;
+
+ void *user_data;
+};
+
+struct drag_offer {
+ struct wl_drag_offer *offer;
+ struct input *input;
+ struct wl_array types;
+ struct window *window;
+ int refcount;
+
+ struct data_transfer transfer;
+
+ float last_x;
+ float last_y;
+
+ void *user_data;
+
+ struct wl_list link;
+};
struct display {
struct wl_display *display;
struct wl_compositor *compositor;
struct wl_shell *shell;
struct wl_shm *shm;
- struct wl_data_device_manager *data_device_manager;
struct text_cursor_position *text_cursor_position;
EGLDisplay dpy;
EGLConfig argb_config;
@@ -153,8 +191,10 @@ struct window {
window_key_handler_t key_handler;
window_keyboard_focus_handler_t keyboard_focus_handler;
- window_data_handler_t data_handler;
+ window_drag_enter_handler_t drag_enter_handler;
+ window_drag_motion_handler_t drag_motion_handler;
window_drop_handler_t drop_handler;
+ window_drag_leave_handler_t drag_leave_handler;
window_close_handler_t close_handler;
struct frame *frame;
@@ -186,6 +226,7 @@ struct input {
struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
+ struct wl_data_transfer *data;
struct window *pointer_focus;
struct window *keyboard_focus;
int current_cursor;
@@ -203,8 +244,8 @@ struct input {
uint32_t grab_button;
struct wl_data_device *data_device;
- struct data_offer *drag_offer;
- struct data_offer *selection_offer;
+ struct wl_list drag_list;
+ struct selection_offer *selection_offer;
struct {
struct xkb_keymap *keymap;
@@ -2121,234 +2162,252 @@ static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_modifiers,
};
+struct input *
+drag_offer_get_input(struct drag_offer *drag)
+{
+ return drag->input;
+}
+
static void
-seat_handle_capabilities(void *data, struct wl_seat *seat,
- enum wl_seat_capability caps)
+drag_offer_unref(struct drag_offer *drag)
{
- struct input *input = data;
+ char **p;
- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
- input->pointer = wl_seat_get_pointer(seat);
- wl_pointer_set_user_data(input->pointer, input);
- wl_pointer_add_listener(input->pointer, &pointer_listener,
- input);
- } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
- wl_pointer_destroy(input->pointer);
- input->pointer = NULL;
- }
+ drag->refcount--;
+ if (drag->refcount > 0)
+ return;
- if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
- input->keyboard = wl_seat_get_keyboard(seat);
- wl_keyboard_set_user_data(input->keyboard, input);
- wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
- input);
- } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
- wl_keyboard_destroy(input->keyboard);
- input->keyboard = NULL;
- }
-}
+ wl_array_for_each(p, &drag->types)
+ free(*p);
+ wl_array_release(&drag->types);
+ wl_list_remove(&drag->link);
-static const struct wl_seat_listener seat_listener = {
- seat_handle_capabilities,
-};
+ wl_drag_offer_destroy(drag->offer);
-void
-input_get_position(struct input *input, int32_t *x, int32_t *y)
-{
- *x = input->sx;
- *y = input->sy;
+ free(drag);
}
-struct display *
-input_get_display(struct input *input)
+static int
+array_is_empty(struct wl_array *array)
{
- return input->display;
-}
+ const char **p;
-struct wl_seat *
-input_get_seat(struct input *input)
-{
- return input->seat;
-}
+ wl_array_for_each(p, array)
+ return 0;
-uint32_t
-input_get_modifiers(struct input *input)
-{
- return input->modifiers;
+ return 1;
}
-struct widget *
-input_get_focus_widget(struct input *input)
+static void
+drag_handle_enter(void *data, struct wl_drag_offer *drag_offer,
+ struct wl_surface *surface, wl_fixed_t x_w,
+ wl_fixed_t y_w)
{
- return input->focus_widget;
-}
+ struct drag_offer *drag = data;
+ struct window *window;
+ float x = wl_fixed_to_double(x_w);
+ float y = wl_fixed_to_double(y_w);
-struct data_offer {
- struct wl_data_offer *offer;
- struct input *input;
- struct wl_array types;
- int refcount;
+ if (!drag)
+ return;
- struct task io_task;
- int fd;
- data_func_t func;
- int32_t x, y;
- void *user_data;
-};
+ if (array_is_empty(&drag->types)) {
+ drag_offer_unref(drag);
+ return;
+ }
+
+ window = wl_surface_get_user_data(surface);
+
+ if (!window->drag_enter_handler) {
+ drag_offer_unref(drag);
+ return;
+ }
+
+ drag->window = window;
+ drag->last_x = x;
+ drag->last_y = y;
+ drag->user_data = window->drag_enter_handler(window, drag, x, y,
+ &drag->types,
+ window->user_data);
+
+ if (!drag->user_data)
+ drag_offer_unref(drag);
+}
static void
-data_offer_offer(void *data, struct wl_data_offer *wl_data_offer, const char *type)
+drag_handle_leave(void *data, struct wl_drag_offer *drag_offer, uint32_t serial)
{
- struct data_offer *offer = data;
- char **p;
+ struct drag_offer *drag = data;
+ struct window *window = drag->window;
- p = wl_array_add(&offer->types, sizeof *p);
- *p = strdup(type);
-}
+ if (!drag)
+ return;
-static const struct wl_data_offer_listener data_offer_listener = {
- data_offer_offer,
-};
+ window->drag_leave_handler(window, drag, drag->user_data);
+
+ drag_offer_unref(drag);
+}
static void
-data_offer_destroy(struct data_offer *offer)
+drag_handle_motion(void *data, struct wl_drag_offer *drag_offer,
+ uint32_t time, wl_fixed_t x_w, wl_fixed_t y_w)
{
- char **p;
+ struct drag_offer *drag = data;
+ struct window *window = drag->window;
+ float x = wl_fixed_to_double(x_w);
+ float y = wl_fixed_to_double(y_w);
- offer->refcount--;
- if (offer->refcount == 0) {
- wl_data_offer_destroy(offer->offer);
- for (p = offer->types.data; *p; p++)
- free(*p);
- wl_array_release(&offer->types);
- free(offer);
- }
+ if (!drag)
+ return;
+
+ drag->last_x = x;
+ drag->last_y = y;
+
+ window->drag_motion_handler(window, drag, x, y, drag->user_data);
}
static void
-data_device_data_offer(void *data,
- struct wl_data_device *data_device,
- struct wl_data_offer *_offer)
+drag_handle_drop(void *data, struct wl_drag_offer *drag_offer)
{
- struct data_offer *offer;
+ struct drag_offer *drag = data;
+ struct window *window = drag->window;
- offer = malloc(sizeof *offer);
+ if (!drag)
+ return;
- wl_array_init(&offer->types);
- offer->refcount = 1;
- offer->input = data;
- offer->offer = _offer;
- wl_data_offer_add_listener(offer->offer,
- &data_offer_listener, offer);
+ window->drop_handler(window, drag, drag->last_x, drag->last_y,
+ window->user_data);
}
static void
-data_device_enter(void *data, struct wl_data_device *data_device,
- uint32_t serial, struct wl_surface *surface,
- wl_fixed_t x_w, wl_fixed_t y_w,
- struct wl_data_offer *offer)
+drag_handle_offer(void *data, struct wl_drag_offer *drag_offer,
+ const char *type)
{
- struct input *input = data;
- struct window *window;
- void *types_data;
- float x = wl_fixed_to_double(x_w);
- float y = wl_fixed_to_double(y_w);
+ struct drag_offer *drag = data;
char **p;
- input->pointer_enter_serial = serial;
- window = wl_surface_get_user_data(surface);
- input->pointer_focus = window;
+ if (!drag || !type)
+ return;
- if (offer) {
- input->drag_offer = wl_data_offer_get_user_data(offer);
+ p = wl_array_add(&drag->types, sizeof *p);
+ if (p)
+ *p = strdup(type);
+ if (!p || !*p)
+ drag_offer_unref(drag);
+}
- p = wl_array_add(&input->drag_offer->types, sizeof *p);
- *p = NULL;
+static const struct wl_drag_offer_listener drag_offer_listener = {
+ drag_handle_enter,
+ drag_handle_leave,
+ drag_handle_motion,
+ drag_handle_drop,
+ drag_handle_offer,
+};
- types_data = input->drag_offer->types.data;
- } else {
- input->drag_offer = NULL;
- types_data = NULL;
- }
+static void
+data_handle_drag(void *data, struct wl_data_transfer *data_transfer,
+ struct wl_drag_offer *offer)
+{
+ struct input *input = data;
+ struct drag_offer *drag;
- window = input->pointer_focus;
- if (window->data_handler)
- window->data_handler(window, input, x, y, types_data,
- window->user_data);
+ drag = malloc(sizeof *drag);
+ if (!drag)
+ return;
+
+ wl_array_init(&drag->types);
+ wl_list_init(&drag->link);
+ drag->input = input;
+ drag->offer = offer;
+ drag->refcount = 1;
+
+ wl_drag_offer_add_listener(offer, &drag_offer_listener, drag);
}
static void
-data_device_leave(void *data, struct wl_data_device *data_device)
+selection_offer_unref(struct selection_offer *selection)
{
- struct input *input = data;
+ char **p;
- if (input->drag_offer) {
- data_offer_destroy(input->drag_offer);
- input->drag_offer = NULL;
- }
+ selection->refcount--;
+ if (selection->refcount > 0)
+ return;
+
+ wl_array_for_each(p, &selection->types)
+ free(*p);
+ wl_array_release(&selection->types);
+
+ free(selection);
}
static void
-data_device_motion(void *data, struct wl_data_device *data_device,
- uint32_t time, wl_fixed_t x_w, wl_fixed_t y_w)
+selection_handle_offer(void *data, struct wl_selection_offer *offer,
+ const char *type)
{
- struct input *input = data;
- struct window *window = input->pointer_focus;
- float x = wl_fixed_to_double(x_w);
- float y = wl_fixed_to_double(y_w);
- void *types_data;
-
- input->sx = x;
- input->sy = y;
+ struct selection_offer *selection = data;
+ char **p;
- if (input->drag_offer)
- types_data = input->drag_offer->types.data;
- else
- types_data = NULL;
+ if (!type)
+ return;
- if (window->data_handler)
- window->data_handler(window, input, x, y, types_data,
- window->user_data);
+ p = wl_array_add(&selection->types, sizeof *p);
+ if (p)
+ *p = strdup(type);
+ if (!p || !*p) {
+ selection_offer_unref(selection);
+ if (selection->input->selection_offer == selection)
+ selection->input->selection_offer = NULL;
+ }
}
static void
-data_device_drop(void *data, struct wl_data_device *data_device)
+selection_handle_cancel(void *data, struct wl_selection_offer *offer)
{
- struct input *input = data;
- struct window *window = input->pointer_focus;
+ struct selection_offer *selection = data;
+
+ selection_offer_unref(selection->input->selection_offer);
- if (window->drop_handler)
- window->drop_handler(window, input,
- input->sx, input->sy, window->user_data);
+ if (selection->input->selection_offer == selection)
+ selection->input->selection_offer = NULL;
}
+static const struct wl_selection_offer_listener selection_offer_listener = {
+ selection_handle_offer,
+ selection_handle_cancel,
+};
+
static void
-data_device_selection(void *data,
- struct wl_data_device *wl_data_device,
- struct wl_data_offer *offer)
+data_handle_selection(void *data, struct wl_data_transfer *data_transfer,
+ struct wl_selection_offer *offer)
{
struct input *input = data;
- char **p;
+ struct selection_offer *selection;
if (input->selection_offer)
- data_offer_destroy(input->selection_offer);
+ selection_offer_unref(input->selection_offer);
+ input->selection_offer = NULL;
- if (offer) {
- input->selection_offer = wl_data_offer_get_user_data(offer);
- p = wl_array_add(&input->selection_offer->types, sizeof *p);
- *p = NULL;
- } else {
- input->selection_offer = NULL;
- }
+ if (!offer)
+ return;
+
+ selection = malloc(sizeof *selection);
+ if (!selection)
+ return;
+
+ wl_array_init(&selection->types);
+ selection->input = input;
+ selection->offer = offer;
+ selection->refcount = 1;
+
+ input->selection_offer = selection;
+ wl_selection_offer_add_listener(selection->offer,
+ &selection_offer_listener,
+ selection);
}
-static const struct wl_data_device_listener data_device_listener = {
- data_device_data_offer,
- data_device_enter,
- data_device_leave,
- data_device_motion,
- data_device_drop,
- data_device_selection
+static const struct wl_data_transfer_listener data_transfer_listener = {
+ data_handle_drag,
+ data_handle_selection,
};
static void
@@ -2460,73 +2519,108 @@ input_set_pointer_image(struct input *input, int pointer)
}
}
-struct wl_data_device *
-input_get_data_device(struct input *input)
+void
+input_set_selection(struct input *input, struct wl_data_source *source,
+ uint32_t serial)
{
- return input->data_device;
+ wl_data_transfer_set_selection(input->data, source, serial);
}
void
-input_set_selection(struct input *input,
- struct wl_data_source *source, uint32_t time)
+input_begin_drag(struct input *input, struct wl_data_source *source,
+ struct window *window, struct wl_surface *icon,
+ uint32_t serial)
{
- wl_data_device_set_selection(input->data_device, source, time);
+ wl_data_transfer_start_drag(input->data, source,
+ window_get_wl_surface(window),
+ icon, serial);
}
void
-input_accept(struct input *input, const char *type)
+input_accept_drag(struct drag_offer *drag, const char *type)
{
- wl_data_offer_accept(input->drag_offer->offer,
- input->pointer_enter_serial, type);
+ wl_drag_offer_accept(drag->offer, type);
+}
+
+void
+input_destroy_drag(struct drag_offer *drag)
+{
+ drag_offer_unref(drag);
}
static void
-offer_io_func(struct task *task, uint32_t events)
+transfer_io_func(struct task *task, uint32_t events)
{
- struct data_offer *offer =
- container_of(task, struct data_offer, io_task);
+ struct data_transfer *transfer =
+ container_of(task, struct data_transfer, io_task);
unsigned int len;
char buffer[4096];
- len = read(offer->fd, buffer, sizeof buffer);
- offer->func(buffer, len,
- offer->x, offer->y, offer->user_data);
+ len = read(transfer->fd, buffer, sizeof buffer);
+ transfer->func(buffer, len, transfer->x, transfer->y,
+ transfer->user_data);
if (len == 0) {
- close(offer->fd);
- data_offer_destroy(offer);
+ close(transfer->fd);
+ transfer->unref(transfer);
}
}
static void
-data_offer_receive_data(struct data_offer *offer, const char *mime_type,
+data_offer_begin_transfer(struct data_transfer *transfer)
+{
+ transfer->io_task.run = transfer_io_func;
+ display_watch_fd(transfer->input->display,
+ transfer->fd, EPOLLIN,
+ &transfer->io_task);
+}
+
+static void
+drag_offer_data_unref(struct data_transfer *transfer)
+{
+ struct drag_offer *drag =
+ container_of(transfer, struct drag_offer, transfer);
+
+ drag_offer_unref(drag);
+}
+
+void
+input_receive_drag_data(struct drag_offer *drag, const char *mime_type,
data_func_t func, void *user_data)
{
- int p[2];
+ int fds[2];
- if (pipe2(p, O_CLOEXEC) == -1)
+ if (pipe2(fds, O_CLOEXEC) == -1)
return;
- wl_data_offer_receive(offer->offer, mime_type, p[1]);
- close(p[1]);
-
- offer->io_task.run = offer_io_func;
- offer->fd = p[0];
- offer->func = func;
- offer->refcount++;
- offer->user_data = user_data;
+ wl_drag_offer_transfer(drag->offer, mime_type, fds[1]);
+ close(fds[1]);
- display_watch_fd(offer->input->display,
- offer->fd, EPOLLIN, &offer->io_task);
+ drag->transfer.input = drag->input;
+ drag->transfer.fd = fds[0];
+ drag->transfer.func = func;
+ drag->transfer.user_data = user_data;
+ drag->transfer.unref = drag_offer_data_unref;
+ drag->transfer.x = drag->last_x;
+ drag->transfer.y = drag->last_y;
+ drag->refcount++;
+ data_offer_begin_transfer(&drag->transfer);
}
void
-input_receive_drag_data(struct input *input, const char *mime_type,
- data_func_t func, void *data)
+input_receive_drag_data_to_fd(struct drag_offer *drag, const char *mime_type,
+ int fd)
+{
+ wl_drag_offer_transfer(drag->offer, mime_type, fd);
+}
+
+static void
+selection_offer_data_unref(struct data_transfer *transfer)
{
- data_offer_receive_data(input->drag_offer, mime_type, func, data);
- input->drag_offer->x = input->sx;
- input->drag_offer->y = input->sy;
+ struct selection_offer *selection =
+ container_of(transfer, struct selection_offer, transfer);
+
+ selection_offer_unref(selection);
}
int
@@ -2534,6 +2628,7 @@ input_receive_selection_data(struct input *input, const char *mime_type,
data_func_t func, void *data)
{
char **p;
+ int fds[2];
if (input->selection_offer == NULL)
return -1;
@@ -2541,26 +2636,112 @@ input_receive_selection_data(struct input *input, const char *mime_type,
for (p = input->selection_offer->types.data; *p; p++)
if (strcmp(mime_type, *p) == 0)
break;
-
if (*p == NULL)
return -1;
- data_offer_receive_data(input->selection_offer,
- mime_type, func, data);
+ if (pipe2(fds, O_CLOEXEC) == -1)
+ return -1;
+
+ wl_selection_offer_transfer(input->selection_offer->offer, mime_type,
+ fds[1]);
+ close(fds[1]);
+
+ input->selection_offer->transfer.input = input;
+ input->selection_offer->transfer.fd = fds[0];
+ input->selection_offer->transfer.func = func;
+ input->selection_offer->transfer.user_data = data;
+ input->selection_offer->transfer.unref = selection_offer_data_unref;
+ input->selection_offer->refcount++;
+ data_offer_begin_transfer(&input->selection_offer->transfer);
+
return 0;
}
int
-input_receive_selection_data_to_fd(struct input *input,
- const char *mime_type, int fd)
+input_receive_selection_data_to_fd(struct input *input, const char *mime_type,
+ int fd)
{
- if (input->selection_offer)
- wl_data_offer_receive(input->selection_offer->offer,
- mime_type, fd);
+ if (!input->selection_offer)
+ return -1;
+
+ wl_selection_offer_transfer(input->selection_offer->offer,
+ mime_type, fd);
return 0;
}
+static void
+seat_handle_capabilities(void *data, struct wl_seat *seat,
+ enum wl_seat_capability caps)
+{
+ struct input *input = data;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
+ input->pointer = wl_seat_get_pointer(seat);
+ wl_pointer_set_user_data(input->pointer, input);
+ wl_pointer_add_listener(input->pointer, &pointer_listener,
+ input);
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
+ wl_pointer_destroy(input->pointer);
+ input->pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
+ input->keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_set_user_data(input->keyboard, input);
+ wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
+ input);
+ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
+ wl_keyboard_destroy(input->keyboard);
+ input->keyboard = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_DATA_TRANSFER) && !input->data) {
+ input->data = wl_seat_get_data_transfer(seat);
+ wl_data_transfer_set_user_data(input->data, input);
+ wl_data_transfer_add_listener(input->data, &data_transfer_listener,
+ input);
+ } else if (!(caps & WL_SEAT_CAPABILITY_DATA_TRANSFER) && input->data) {
+ wl_data_transfer_destroy(input->data);
+ input->data = NULL;
+ }
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_handle_capabilities,
+};
+
+void
+input_get_position(struct input *input, int32_t *x, int32_t *y)
+{
+ *x = input->sx;
+ *y = input->sy;
+}
+
+struct display *
+input_get_display(struct input *input)
+{
+ return input->display;
+}
+
+struct wl_seat *
+input_get_seat(struct input *input)
+{
+ return input->seat;
+}
+
+uint32_t
+input_get_modifiers(struct input *input)
+{
+ return input->modifiers;
+}
+
+struct widget *
+input_get_focus_widget(struct input *input)
+{
+ return input->focus_widget;
+}
+
void
window_move(struct window *window, struct input *input, uint32_t serial)
{
@@ -2810,9 +2991,24 @@ window_set_keyboard_focus_handler(struct window *window,
}
void
-window_set_data_handler(struct window *window, window_data_handler_t handler)
+window_set_drag_enter_handler(struct window *window,
+ window_drag_enter_handler_t handler)
{
- window->data_handler = handler;
+ window->drag_enter_handler = handler;
+}
+
+void
+window_set_drag_motion_handler(struct window *window,
+ window_drag_motion_handler_t handler)
+{
+ window->drag_motion_handler = handler;
+}
+
+void
+window_set_drag_leave_handler(struct window *window,
+ window_drag_leave_handler_t handler)
+{
+ window->drag_leave_handler = handler;
}
void
@@ -3318,15 +3514,10 @@ display_add_input(struct display *d, uint32_t id)
input->keyboard_focus = NULL;
wl_list_insert(d->input_list.prev, &input->link);
+ wl_list_init(&input->drag_list);
wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
- input->data_device =
- wl_data_device_manager_get_data_device(d->data_device_manager,
- input->seat);
- wl_data_device_add_listener(input->data_device, &data_device_listener,
- input);
-
input->pointer_surface = wl_compositor_create_surface(d->compositor);
input->repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC,
@@ -3339,16 +3530,22 @@ display_add_input(struct display *d, uint32_t id)
static void
input_destroy(struct input *input)
{
+ struct drag_offer *drag, *tmp;
+
input_remove_keyboard_focus(input);
input_remove_pointer_focus(input);
- if (input->drag_offer)
- data_offer_destroy(input->drag_offer);
+ wl_list_for_each_safe(drag, tmp, &input->drag_list, link)
+ drag_offer_unref(drag);
+#if 0
if (input->selection_offer)
- data_offer_destroy(input->selection_offer);
+ selection_offer_destroy(input->selection_offer);
+
+ if (input->data)
+ wl_data_transfer_destroy(input->data);
+#endif
- wl_data_device_destroy(input->data_device);
fini_xkb(input);
wl_surface_destroy(input->pointer_surface);
@@ -3376,10 +3573,6 @@ display_handle_global(struct wl_display *display, uint32_t id,
d->shell = wl_display_bind(display, id, &wl_shell_interface);
} else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_display_bind(display, id, &wl_shm_interface);
- } else if (strcmp(interface, "wl_data_device_manager") == 0) {
- d->data_device_manager =
- wl_display_bind(display, id,
- &wl_data_device_manager_interface);
} else if (strcmp(interface, "text_cursor_position") == 0) {
d->text_cursor_position =
wl_display_bind(display, id,
@@ -3603,9 +3796,6 @@ display_destroy(struct display *display)
if (display->shm)
wl_shm_destroy(display->shm);
- if (display->data_device_manager)
- wl_data_device_manager_destroy(display->data_device_manager);
-
wl_compositor_destroy(display->compositor);
close(display->epoll_fd);
@@ -3658,9 +3848,9 @@ display_get_egl_display(struct display *d)
}
struct wl_data_source *
-display_create_data_source(struct display *display)
+input_create_data_source(struct input *input)
{
- return wl_data_device_manager_create_data_source(display->data_device_manager);
+ return wl_data_transfer_create_data_source(input->data);
}
EGLConfig
diff --git a/clients/window.h b/clients/window.h
index de38647..c23c659 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -33,6 +33,7 @@ struct widget;
struct display;
struct input;
struct output;
+struct drag_offer;
struct task {
void (*run)(struct task *task, uint32_t events);
@@ -87,7 +88,7 @@ display_set_output_configure_handler(struct display *display,
display_output_handler_t handler);
struct wl_data_source *
-display_create_data_source(struct display *display);
+input_create_data_source(struct input *input);
#ifdef EGL_NO_DISPLAY
EGLDisplay
@@ -165,15 +166,22 @@ typedef void (*window_key_handler_t)(struct window *window, struct input *input,
typedef void (*window_keyboard_focus_handler_t)(struct window *window,
struct input *device, void *data);
-typedef void (*window_data_handler_t)(struct window *window,
- struct input *input,
+typedef void *(*window_drag_enter_handler_t)(struct window *window,
+ struct drag_offer *drag,
+ float x, float y,
+ struct wl_array *types,
+ void *window_data);
+typedef void (*window_drag_motion_handler_t)(struct window *window,
+ struct drag_offer *drag,
+ float x, float y,
+ void *data);
+typedef void (*window_drop_handler_t)(struct window *window,
+ struct drag_offer *drag,
float x, float y,
- const char **types,
void *data);
-
-typedef void (*window_drop_handler_t)(struct window *window,
- struct input *input,
- int32_t x, int32_t y, void *data);
+typedef void (*window_drag_leave_handler_t)(struct window *window,
+ struct drag_offer *drag,
+ void *data);
typedef void (*window_close_handler_t)(struct window *window, void *data);
@@ -293,14 +301,22 @@ window_set_keyboard_focus_handler(struct window *window,
window_keyboard_focus_handler_t handler);
void
-window_set_data_handler(struct window *window,
- window_data_handler_t handler);
+window_set_drag_enter_handler(struct window *window,
+ window_drag_enter_handler_t handler);
+
+void
+window_set_drag_motion_handler(struct window *window,
+ window_drag_motion_handler_t handler);
void
window_set_drop_handler(struct window *window,
window_drop_handler_t handler);
void
+window_set_drag_leave_handler(struct window *window,
+ window_drag_leave_handler_t handler);
+
+void
window_set_close_handler(struct window *window,
window_close_handler_t handler);
@@ -399,16 +415,29 @@ struct wl_data_device *
input_get_data_device(struct input *input);
void
-input_set_selection(struct input *input,
- struct wl_data_source *source, uint32_t time);
+input_set_selection(struct input *input, struct wl_data_source *source,
+ uint32_t serial);
void
-input_accept(struct input *input, const char *type);
+input_accept_drag(struct drag_offer *drag, const char *type);
+void
+input_reject_drag(struct drag_offer *drag);
+
+void
+input_begin_drag(struct input *input, struct wl_data_source *source,
+ struct window *window, struct wl_surface *icon,
+ uint32_t serial);
void
-input_receive_drag_data(struct input *input, const char *mime_type,
+input_receive_drag_data(struct drag_offer *drag, const char *mime_type,
data_func_t func, void *user_data);
+void
+input_receive_drag_data_to_fd(struct drag_offer *drag, const char *mime_type,
+ int fd);
+
+void
+input_destroy_drag(struct drag_offer *drag);
int
input_receive_selection_data(struct input *input, const char *mime_type,
@@ -418,6 +447,12 @@ input_receive_selection_data_to_fd(struct input *input,
const char *mime_type, int fd);
void
+input_destroy_selection(struct drag_offer *drag);
+
+struct input *
+drag_offer_get_input(struct drag_offer *drag);
+
+void
output_set_user_data(struct output *output, void *data);
void *
diff --git a/src/clipboard.c b/src/clipboard.c
index 7db5d04..641fed4 100644
--- a/src/clipboard.c
+++ b/src/clipboard.c
@@ -60,8 +60,8 @@ clipboard_source_unref(struct clipboard_source *source)
if (source->event_source)
wl_event_source_remove(source->event_source);
- wl_signal_emit(&source->base.resource.destroy_signal,
- &source->base.resource);
+ wl_signal_emit(&source->base.resource->destroy_signal,
+ source->base.resource);
s = source->base.mime_types.data;
free(*s);
wl_array_release(&source->base.mime_types);
@@ -99,8 +99,7 @@ clipboard_source_data(int fd, uint32_t mask, void *data)
}
static void
-clipboard_source_accept(struct wl_data_source *source,
- uint32_t time, const char *mime_type)
+clipboard_source_accept(struct wl_data_source *source, const char *mime_type)
{
}
@@ -134,13 +133,20 @@ clipboard_source_create(struct clipboard *clipboard,
char **s;
source = malloc(sizeof *source);
+ if (!source)
+ return NULL;
+ source->base.resource = malloc(sizeof *source->base.resource);
+ if (source->base.resource) {
+ free(source);
+ return NULL;
+ }
wl_array_init(&source->contents);
wl_array_init(&source->base.mime_types);
source->base.accept = clipboard_source_accept;
source->base.send = clipboard_source_send;
source->base.cancel = clipboard_source_cancel;
- source->base.resource.data = &source->base;
- wl_signal_init(&source->base.resource.destroy_signal);
+ source->base.resource->data = &source->base;
+ wl_signal_init(&source->base.resource->destroy_signal);
source->refcount = 1;
source->clipboard = clipboard;
source->serial = serial;
diff --git a/src/compositor.c b/src/compositor.c
index 92abab1..143bef7 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1850,10 +1850,8 @@ weston_surface_activate(struct weston_surface *surface,
{
struct weston_compositor *compositor = seat->compositor;
- if (seat->seat.keyboard) {
+ if (seat->seat.keyboard)
wl_keyboard_set_focus(seat->seat.keyboard, &surface->surface);
- wl_data_device_set_keyboard_focus(&seat->seat);
- }
wl_signal_emit(&compositor->activate_signal, surface);
}
@@ -2313,17 +2311,6 @@ static const struct wl_pointer_interface pointer_interface = {
pointer_set_cursor
};
-static void
-handle_drag_surface_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_seat *seat;
-
- seat = container_of(listener, struct weston_seat,
- drag_surface_destroy_listener);
-
- seat->drag_surface = NULL;
-}
-
static void unbind_resource(struct wl_resource *resource)
{
wl_list_remove(&resource->link);
@@ -2404,10 +2391,20 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource,
cr->destroy = unbind_resource;
}
+static void
+seat_get_data_transfer(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id)
+{
+ struct weston_seat *seat = resource->data;
+
+ wl_seat_new_data_transfer(&seat->seat, client, id);
+}
+
static const struct wl_seat_interface seat_interface = {
seat_get_pointer,
seat_get_keyboard,
seat_get_touch,
+ seat_get_data_transfer,
};
static void
@@ -2415,13 +2412,15 @@ bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct wl_seat *seat = data;
struct wl_resource *resource;
- enum wl_seat_capability caps = 0;
+ enum wl_seat_capability caps;
resource = wl_client_add_object(client, &wl_seat_interface,
&seat_interface, id, data);
wl_list_insert(&seat->base_resource_list, &resource->link);
resource->destroy = unbind_resource;
+ caps = WL_SEAT_CAPABILITY_DATA_TRANSFER;
+
if (seat->pointer)
caps |= WL_SEAT_CAPABILITY_POINTER;
if (seat->keyboard)
@@ -2634,9 +2633,6 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec)
seat->modifier_state = 0;
seat->num_tp = 0;
- seat->drag_surface_destroy_listener.notify =
- handle_drag_surface_destroy;
-
wl_list_insert(ec->seat_list.prev, &seat->link);
clipboard_create(seat);
@@ -3067,8 +3063,6 @@ weston_compositor_init(struct weston_compositor *ec,
text_cursor_position_notifier_create(ec);
input_method_create(ec);
- wl_data_device_manager_init(ec->wl_display);
-
wl_display_init_shm(display);
loop = wl_display_get_event_loop(ec->wl_display);
diff --git a/src/xwayland/selection.c b/src/xwayland/selection.c
index 21fbb59..0bdc9b7 100644
--- a/src/xwayland/selection.c
+++ b/src/xwayland/selection.c
@@ -112,8 +112,7 @@ struct x11_data_source {
};
static void
-data_source_accept(struct wl_data_source *source,
- uint32_t time, const char *mime_type)
+data_source_accept(struct wl_data_source *source, const char *mime_type)
{
}
@@ -177,11 +176,16 @@ weston_wm_get_selection_targets(struct weston_wm *wm)
if (source == NULL)
return;
- wl_signal_init(&source->base.resource.destroy_signal);
+ source->base.resource = malloc(sizeof *source->base.resource);
+ if (source->base.resource == NULL) {
+ free(source);
+ return;
+ }
+ wl_signal_init(&source->base.resource->destroy_signal);
source->base.accept = data_source_accept;
source->base.send = data_source_send;
source->base.cancel = data_source_cancel;
- source->base.resource.data = source;
+ source->base.resource->data = source;
source->wm = wm;
wl_array_init(&source->base.mime_types);
--
1.7.10.4
More information about the wayland-devel
mailing list