diff options
author | Kristian Høgsberg <krh@bitplanet.net> | 2011-10-28 12:26:06 -0400 |
---|---|---|
committer | Kristian Høgsberg <krh@bitplanet.net> | 2011-11-23 16:20:28 -0500 |
commit | 47fe08aad5ccca95ff433d6475e14528f13b0791 (patch) | |
tree | 87b7b8b1970e98807ed97d19c1fba80397d4e262 /clients | |
parent | f02bb64d62d0eea8fcb4c294f5ec13cd94e3440b (diff) |
Implement the new dnd/selection protocol
The new protocol splits dnd/selection from wl_shell and allows us to move
the implementation out of shell.c.
Diffstat (limited to 'clients')
-rw-r--r-- | clients/dnd.c | 370 | ||||
-rw-r--r-- | clients/terminal.c | 74 | ||||
-rw-r--r-- | clients/window.c | 396 | ||||
-rw-r--r-- | clients/window.h | 59 |
4 files changed, 477 insertions, 422 deletions
diff --git a/clients/dnd.c b/clients/dnd.c index db794fd..5ec3ba3 100644 --- a/clients/dnd.c +++ b/clients/dnd.c @@ -30,7 +30,6 @@ #include <sys/time.h> #include <cairo.h> #include <sys/epoll.h> -#include <gdk-pixbuf/gdk-pixbuf.h> #include <wayland-client.h> @@ -54,17 +53,8 @@ struct dnd_drag { struct item *item; int x_offset, y_offset; const char *mime_type; -}; -struct dnd_offer { - int refcount; - struct dnd *dnd; - struct wl_array types; - struct task io_task; - const char *drag_type; - uint32_t tag; - int x, y; - int fd; + struct wl_data_source *data_source; }; struct item { @@ -183,25 +173,21 @@ dnd_draw(struct dnd *dnd) window_get_child_allocation(dnd->window, &allocation); cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height); - cairo_clip(cr); - cairo_push_group(cr); - cairo_translate(cr, allocation.x, allocation.y); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0, 0, 0, 0.8); - cairo_paint(cr); + cairo_fill(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) { if (!dnd->items[i]) continue; cairo_set_source_surface(cr, dnd->items[i]->surface, - dnd->items[i]->x, dnd->items[i]->y); + dnd->items[i]->x + allocation.x, + dnd->items[i]->y + allocation.y); cairo_paint(cr); } - cairo_pop_group_to_source(cr); - cairo_paint(cr); cairo_destroy(cr); cairo_surface_destroy(surface); window_flush(dnd->window); @@ -224,16 +210,6 @@ keyboard_focus_handler(struct window *window, window_schedule_redraw(dnd->window); } -static void -dnd_offer_destroy(struct dnd_offer *dnd_offer) -{ - dnd_offer->refcount--; - if (dnd_offer->refcount == 0) { - wl_array_release(&dnd_offer->types); - free(dnd_offer); - } -} - static int dnd_add_item(struct dnd *dnd, struct item *item) { @@ -272,17 +248,16 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y) } static void -drag_target(void *data, - struct wl_drag *drag, const char *mime_type) +data_source_target(void *data, + struct wl_data_source *source, const char *mime_type) { struct dnd_drag *dnd_drag = data; struct dnd *dnd = dnd_drag->dnd; - struct wl_input_device *device; cairo_surface_t *surface; struct wl_buffer *buffer; + struct wl_data_device *device; - fprintf(stderr, "target %s\n", mime_type); - device = input_get_input_device(dnd_drag->input); + device = input_get_data_device(dnd_drag->input); dnd_drag->mime_type = mime_type; if (mime_type) surface = dnd_drag->opaque; @@ -290,38 +265,35 @@ drag_target(void *data, surface = dnd_drag->translucent; buffer = display_get_buffer_for_surface(dnd->display, surface); - wl_input_device_attach(device, dnd_drag->time, buffer, - dnd_drag->hotspot_x, dnd_drag->hotspot_y); + wl_data_device_attach(device, dnd_drag->time, buffer, + dnd_drag->hotspot_x, dnd_drag->hotspot_y); } static void -drag_finish(void *data, struct wl_drag *drag, int fd) +data_source_send(void *data, struct wl_data_source *source, + const char *mime_type, int32_t fd) { - struct dnd_drag *dnd_drag = data; - - if (!dnd_drag->mime_type) { - dnd_add_item(dnd_drag->dnd, dnd_drag->item); - window_schedule_redraw(dnd_drag->dnd->window); - return; - } - 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; - fprintf(stderr, "got 'finish', fd %d, sending dnd_flower_message\n", fd); - write(fd, &dnd_flower_message, sizeof dnd_flower_message); close(fd); +} + +static void +data_source_cancelled(void *data, struct wl_data_source *source) +{ + struct dnd_drag *dnd_drag = data; - /* The 'finish' event marks the end of the session on the drag - * source side and we need to clean up the drag object created - * and the local state. */ - wl_drag_destroy(drag); + /* The 'cancelled' event means that the source is no longer in + * use by the drag (or current selection). We need to clean + * 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); @@ -332,178 +304,12 @@ drag_finish(void *data, struct wl_drag *drag, int fd) free(dnd_drag); } -static void -drag_reject(void *data, struct wl_drag *drag) -{ - struct dnd_drag *dnd_drag = data; - - dnd_add_item(dnd_drag->dnd, dnd_drag->item); - window_schedule_redraw(dnd_drag->dnd->window); -} - -static const struct wl_drag_listener drag_listener = { - drag_target, - drag_finish, - drag_reject -}; - -static void -drag_offer_offer(void *data, - struct wl_drag_offer *offer, const char *type) -{ - struct dnd_offer *dnd_offer = data; - char **p; - - p = wl_array_add(&dnd_offer->types, sizeof *p); - if (p) - *p = strdup(type); -} - -static void -drag_offer_pointer_focus(void *data, - struct wl_drag_offer *offer, - uint32_t time, struct wl_surface *surface, - int32_t x, int32_t y, - int32_t surface_x, int32_t surface_y) -{ - struct dnd_offer *dnd_offer = data; - struct window *window; - char **p, **end; - - /* The last event in a dnd session is pointer_focus with a - * NULL surface, whether or not we get the drop event. We - * need to clean up the dnd_offer proxy and whatever state we - * allocated. */ - if (!surface) { - fprintf(stderr, "pointer focus NULL, session over\n"); - wl_drag_offer_destroy(offer); - dnd_offer_destroy(dnd_offer); - return; - } - - fprintf(stderr, "drag pointer focus %p\n", surface); - fprintf(stderr, "offered types:\n"); - end = dnd_offer->types.data + dnd_offer->types.size; - for (p = dnd_offer->types.data; p < end; p++) - fprintf(stderr, "\%s\n", *p); - - window = wl_surface_get_user_data(surface); - dnd_offer->dnd = window_get_user_data(window); - - if (!dnd_get_item(dnd_offer->dnd, surface_x, surface_y)) { - wl_drag_offer_accept(offer, time, "application/x-wayland-dnd-flower"); - dnd_offer->drag_type = "application/x-wayland-dnd-flower"; - dnd_offer->x = surface_x; - dnd_offer->y = surface_y; - } else { - wl_drag_offer_accept(offer, time, NULL); - dnd_offer->drag_type = NULL; - } -} - -static void -drag_offer_motion(void *data, - struct wl_drag_offer *offer, uint32_t time, - int32_t x, int32_t y, int32_t surface_x, int32_t surface_y) -{ - struct dnd_offer *dnd_offer = data; - - if (!dnd_get_item(dnd_offer->dnd, surface_x, surface_y)) { - fprintf(stderr, "drag offer motion %d, %d, accepting\n", - surface_x, surface_y); - wl_drag_offer_accept(offer, time, "application/x-wayland-dnd-flower"); - dnd_offer->drag_type = "application/x-wayland-dnd-flower"; - dnd_offer->x = surface_x; - dnd_offer->y = surface_y; - } else { - fprintf(stderr, "drag offer motion %d, %d, declining\n", - surface_x, surface_y); - wl_drag_offer_accept(offer, time, NULL); - dnd_offer->drag_type = NULL; - } -} - -static void -drop_io_func(struct task *task, uint32_t events) -{ - struct dnd_offer *dnd_offer = - container_of(task, struct dnd_offer, io_task); - struct dnd *dnd = dnd_offer->dnd; - struct dnd_flower_message dnd_flower_message; - unsigned int len; - struct item *item; - - len = read(dnd_offer->fd, - &dnd_flower_message, sizeof dnd_flower_message); - fprintf(stderr, "read %d bytes\n", len); - - close(dnd_offer->fd); - - item = item_create(dnd->display, - dnd_offer->x - dnd_flower_message.x_offset - 26, - dnd_offer->y - dnd_flower_message.y_offset - 66, - dnd_flower_message.seed); - - dnd_add_item(dnd, item); - window_schedule_redraw(dnd->window); - - dnd_offer_destroy(dnd_offer); -} - -static void -drag_offer_drop(void *data, struct wl_drag_offer *offer) -{ - struct dnd_offer *dnd_offer = data; - int p[2]; - - if (!dnd_offer->drag_type) { - fprintf(stderr, "got 'drop', but no target\n"); - wl_drag_offer_reject(offer); - return; - } - - fprintf(stderr, "got 'drop', sending write end of pipe\n"); - - dnd_offer->refcount++; - pipe(p); - wl_drag_offer_receive(offer, p[1]); - close(p[1]); - - dnd_offer->io_task.run = drop_io_func; - dnd_offer->fd = p[0]; - display_watch_fd(dnd_offer->dnd->display, - p[0], EPOLLIN, &dnd_offer->io_task); -} - -static const struct wl_drag_offer_listener drag_offer_listener = { - drag_offer_offer, - drag_offer_pointer_focus, - drag_offer_motion, - drag_offer_drop, +static const struct wl_data_source_listener data_source_listener = { + data_source_target, + data_source_send, + data_source_cancelled }; -static void -global_handler(struct wl_display *display, uint32_t id, - const char *interface, uint32_t version, void *data) -{ - struct wl_drag_offer *offer; - struct dnd_offer *dnd_offer; - - if (strcmp(interface, "wl_drag_offer") != 0) - return; - - offer = wl_display_bind(display, id, &wl_drag_offer_interface); - - dnd_offer = malloc(sizeof *dnd_offer); - if (dnd_offer == NULL) - return; - - dnd_offer->refcount = 1; - - wl_drag_offer_add_listener(offer, &drag_offer_listener, dnd_offer); - wl_array_init(&dnd_offer->types); -} - static cairo_surface_t * create_drag_cursor(struct dnd_drag *dnd_drag, struct item *item, int32_t x, int32_t y, double opacity) @@ -564,7 +370,6 @@ dnd_button_handler(struct window *window, struct item *item; struct rectangle allocation; struct dnd_drag *dnd_drag; - struct wl_drag *drag; int i; window_get_child_allocation(dnd->window, &allocation); @@ -574,8 +379,6 @@ dnd_button_handler(struct window *window, y -= allocation.y; if (item && state == 1) { - fprintf(stderr, "start drag, item %p\n", item); - dnd_drag = malloc(sizeof *dnd_drag); dnd_drag->dnd = dnd; dnd_drag->input = input; @@ -591,34 +394,114 @@ dnd_button_handler(struct window *window, } } + 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(window), + time); + + input_set_pointer_image(input, time, POINTER_DRAGGING); + 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); - drag = window_create_drag(window); - wl_drag_offer(drag, "application/x-wayland-dnd-flower"); - window_activate_drag(drag, window, input, time); - wl_drag_add_listener(drag, &drag_listener, dnd_drag); window_schedule_redraw(dnd->window); } } static int +lookup_cursor(struct dnd *dnd, int x, int y) +{ + struct item *item; + + item = dnd_get_item(dnd, x, y); + if (item) + return POINTER_HAND1; + else + return POINTER_LEFT_PTR; +} + +static int +dnd_enter_handler(struct window *window, + struct input *input, uint32_t time, + int32_t x, int32_t y, void *data) +{ + return lookup_cursor(data, x, y); +} + +static int dnd_motion_handler(struct window *window, struct input *input, uint32_t time, int32_t x, int32_t y, int32_t sx, int32_t sy, void *data) { + return lookup_cursor(data, sx, sy); +} + +static void +dnd_data_handler(struct window *window, + struct input *input, uint32_t time, + int32_t x, int32_t y, const char **types, void *data) +{ struct dnd *dnd = data; + + if (!dnd_get_item(dnd, x, y)) { + input_accept(input, time, types[0]); + } else { + input_accept(input, time, NULL); + } +} + +static void +dnd_receive_func(void *data, size_t len, int32_t x, int32_t y, void *user_data) +{ + struct dnd *dnd = user_data; + struct dnd_flower_message *message = data; struct item *item; + struct rectangle allocation; - item = dnd_get_item(dnd, sx, sy); + if (len == 0) { + return; + } else if (len != sizeof *message) { + fprintf(stderr, "odd message length %ld, expected %ld\n", + len, sizeof *message); + return; + } + + window_get_child_allocation(dnd->window, &allocation); + item = item_create(dnd->display, + x - message->x_offset - allocation.x, + y - message->y_offset - allocation.y, + message->seed); - if (item) - return POINTER_HAND1; - else - return POINTER_LEFT_PTR; + dnd_add_item(dnd, item); + window_schedule_redraw(dnd->window); +} + +static void +dnd_drop_handler(struct window *window, struct input *input, + int32_t x, int32_t y, void *data) +{ + struct dnd *dnd = data; + + if (dnd_get_item(dnd, x, y)) { + fprintf(stderr, "got 'drop', but no target\n"); + return; + } + + input_receive_drag_data(input, + "application/x-wayland-dnd-flower", + dnd_receive_func, dnd); } static struct dnd * @@ -639,9 +522,6 @@ dnd_create(struct display *display) dnd->display = display; dnd->key = 100; - wl_display_add_global_listener(display_get_display(display), - global_handler, dnd); - for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) { x = (i % 4) * (item_width + item_padding) + item_padding; y = (i / 4) * (item_height + item_padding) + item_padding; @@ -655,11 +535,11 @@ dnd_create(struct display *display) window_set_redraw_handler(dnd->window, redraw_handler); window_set_keyboard_focus_handler(dnd->window, keyboard_focus_handler); - window_set_button_handler(dnd->window, - dnd_button_handler); - - window_set_motion_handler(dnd->window, - dnd_motion_handler); + window_set_button_handler(dnd->window, dnd_button_handler); + window_set_enter_handler(dnd->window, dnd_enter_handler); + window_set_motion_handler(dnd->window, dnd_motion_handler); + window_set_data_handler(dnd->window, dnd_data_handler); + window_set_drop_handler(dnd->window, dnd_drop_handler); width = 4 * (item_width + item_padding) + item_padding; height = 4 * (item_height + item_padding) + item_padding; @@ -670,16 +550,12 @@ dnd_create(struct display *display) return dnd; } -static const GOptionEntry option_entries[] = { - { NULL } -}; - int main(int argc, char *argv[]) { struct display *d; - d = display_create(&argc, &argv, option_entries); + d = display_create(&argc, &argv, NULL); if (d == NULL) { fprintf(stderr, "failed to create display: %m\n"); return -1; diff --git a/clients/terminal.c b/clients/terminal.c index 8651073..472fb2a 100644 --- a/clients/terminal.c +++ b/clients/terminal.c @@ -390,10 +390,8 @@ struct terminal { cairo_font_extents_t extents; cairo_scaled_font_t *font_normal, *font_bold; - struct wl_selection *selection; - struct wl_selection_offer *selection_offer; - uint32_t selection_offer_has_text; - int32_t dragging, selection_active; + struct wl_data_source *selection; + int32_t dragging; int selection_start_x, selection_start_y; int selection_end_x, selection_end_y; }; @@ -2026,55 +2024,65 @@ terminal_data(struct terminal *terminal, const char *data, size_t length) } static void -selection_listener_send(void *data, struct wl_selection *selection, - const char *mime_type, int fd) +data_source_target(void *data, + struct wl_data_source *source, const char *mime_type) +{ + fprintf(stderr, "data_source_target, %s\n", mime_type); +} + +static void +data_source_send(void *data, + struct wl_data_source *source, + const char *mime_type, int32_t fd) { struct terminal *terminal = data; - fprintf(stderr, "selection send, fd is %d\n", fd); terminal_send_selection(terminal, fd); close(fd); } static void -selection_listener_cancelled(void *data, struct wl_selection *selection) +data_source_cancelled(void *data, struct wl_data_source *source) { - fprintf(stderr, "selection cancelled\n"); - wl_selection_destroy(selection); + wl_data_source_destroy(source); } -static const struct wl_selection_listener selection_listener = { - selection_listener_send, - selection_listener_cancelled +static const struct wl_data_source_listener data_source_listener = { + data_source_target, + data_source_send, + data_source_cancelled }; +static void selection_receive_func(void *data, size_t len, + int32_t x, int32_t y, void *user_data) +{ + struct terminal *terminal = user_data; + + write(terminal->master, data, len); +} + static int handle_bound_key(struct terminal *terminal, struct input *input, uint32_t sym, uint32_t time) { - struct wl_shell *shell; - switch (sym) { + case XK_X: + /* Cut selection; terminal doesn't do cut, fall + * through to copy. */ case XK_C: - shell = display_get_shell(terminal->display); - terminal->selection = wl_shell_create_selection(shell); - wl_selection_add_listener(terminal->selection, - &selection_listener, terminal); - wl_selection_offer(terminal->selection, "text/plain"); - wl_selection_activate(terminal->selection, - input_get_input_device(input), time); - + terminal->selection = + display_create_data_source(terminal->display); + wl_data_source_offer(terminal->selection, + "text/plain; charset=utf-8"); + wl_data_source_add_listener(terminal->selection, + &data_source_listener, terminal); + input_set_selection(input, terminal->selection, time); return 1; case XK_V: - /* Just pass the master fd of the pty to receive the - * selection. */ - if (input_offers_mime_type(input, "text/plain")) - input_receive_mime_type(input, "text/plain", - terminal->master); + input_receive_selection_data(input, + "text/plain; charset=utf-8", + selection_receive_func, terminal); return 1; - case XK_X: - /* cut selection; terminal doesn't do cut */ - return 0; default: return 0; } @@ -2092,7 +2100,7 @@ key_handler(struct window *window, struct input *input, uint32_t time, modifiers = input_get_modifiers(input); if ((modifiers & XKB_COMMON_CONTROL_MASK) && (modifiers & XKB_COMMON_SHIFT_MASK) && - state && handle_bound_key(terminal, input, sym, 0)) + state && handle_bound_key(terminal, input, sym, time)) return; switch (sym) { @@ -2234,7 +2242,6 @@ button_handler(struct window *window, case 272: if (state) { terminal->dragging = 1; - terminal->selection_active = 0; input_get_position(input, &terminal->selection_start_x, &terminal->selection_start_y); @@ -2257,7 +2264,6 @@ motion_handler(struct window *window, struct terminal *terminal = data; if (terminal->dragging) { - terminal->selection_active = 1; input_get_position(input, &terminal->selection_end_x, &terminal->selection_end_y); diff --git a/clients/window.c b/clients/window.c index 1e317c7..32c546d 100644 --- a/clients/window.c +++ b/clients/window.c @@ -20,6 +20,8 @@ * OF THIS SOFTWARE. */ +#define _GNU_SOURCE + #include "../config.h" #include <stdint.h> @@ -61,6 +63,7 @@ struct display { struct wl_shell *shell; struct wl_shm *shm; struct wl_output *output; + struct wl_data_device_manager *data_device_manager; struct rectangle screen_allocation; EGLDisplay dpy; EGLConfig rgb_config; @@ -127,6 +130,8 @@ struct window { window_enter_handler_t enter_handler; window_leave_handler_t leave_handler; window_item_focus_handler_t item_focus_handler; + window_data_handler_t data_handler; + window_drop_handler_t drop_handler; struct wl_list item_list; struct item *focus_item; @@ -147,11 +152,14 @@ struct input { struct wl_input_device *input_device; struct window *pointer_focus; struct window *keyboard_focus; - struct selection_offer *offer; uint32_t current_pointer_image; uint32_t modifiers; int32_t x, y, sx, sy; struct wl_list link; + + struct wl_data_device *data_device; + struct data_offer *drag_offer; + struct data_offer *selection_offer; }; enum { @@ -695,7 +703,6 @@ display_get_pointer_surface(struct display *display, int pointer, return cairo_surface_reference(surface); } - static void window_attach_surface(struct window *window); @@ -1132,8 +1139,8 @@ get_pointer_location(struct window *window, int32_t x, int32_t y) return location; } -static void -set_pointer_image(struct input *input, uint32_t time, int pointer) +void +input_set_pointer_image(struct input *input, uint32_t time, int pointer) { struct display *display = input->display; struct wl_buffer *buffer; @@ -1233,7 +1240,7 @@ window_handle_motion(void *data, struct wl_input_device *input_device, x, y, sx, sy, window->user_data); - set_pointer_image(input, time, pointer); + input_set_pointer_image(input, time, pointer); } static void @@ -1364,7 +1371,7 @@ window_handle_pointer_focus(void *data, item = window_find_item(window, x, y); window_set_focus_item(window, item); - set_pointer_image(input, time, pointer); + input_set_pointer_image(input, time, pointer); } } @@ -1435,28 +1442,246 @@ input_get_modifiers(struct input *input) return input->modifiers; } -struct wl_drag * -window_create_drag(struct window *window) +struct data_offer { + struct wl_data_offer *offer; + struct input *input; + struct wl_array types; + int refcount; + + struct task io_task; + int fd; + data_func_t func; + int32_t x, y; + void *user_data; +}; + +static void +data_offer_offer(void *data, struct wl_data_offer *wl_data_offer, const char *type) +{ + struct data_offer *offer = data; + char **p; + + p = wl_array_add(&offer->types, sizeof *p); + *p = strdup(type); +} + +static const struct wl_data_offer_listener data_offer_listener = { + data_offer_offer, +}; + +static void +data_offer_destroy(struct data_offer *offer) { - cairo_device_flush (window->display->rgb_device); - cairo_device_flush (window->display->argb_device); + char **p; - return wl_shell_create_drag(window->display->shell); + 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); + } +} + +static void +data_device_data_offer(void *data, + struct wl_data_device *data_device, uint32_t id) +{ + struct data_offer *offer; + + offer = malloc(sizeof *offer); + + wl_array_init(&offer->types); + offer->refcount = 1; + offer->input = data; + + /* FIXME: Generate typesafe wrappers for this */ + offer->offer = (struct wl_data_offer *) + wl_proxy_create_for_id((struct wl_proxy *) data_device, + id, &wl_data_offer_interface); + + wl_data_offer_add_listener(offer->offer, + &data_offer_listener, offer); +} + +static void +data_device_enter(void *data, struct wl_data_device *data_device, + uint32_t time, struct wl_surface *surface, + int32_t x, int32_t y, struct wl_data_offer *offer) +{ + struct input *input = data; + struct window *window; + char **p; + + input->drag_offer = wl_data_offer_get_user_data(offer); + window = wl_surface_get_user_data(surface); + input->pointer_focus = window; + + p = wl_array_add(&input->drag_offer->types, sizeof *p); + *p = NULL; + + window = input->pointer_focus; + if (window->data_handler) + window->data_handler(window, input, time, x, y, + input->drag_offer->types.data, + window->user_data); +} + +static void +data_device_leave(void *data, struct wl_data_device *data_device) +{ + struct input *input = data; + + data_offer_destroy(input->drag_offer); + input->drag_offer = NULL; +} + +static void +data_device_motion(void *data, struct wl_data_device *data_device, + uint32_t time, int32_t x, int32_t y) +{ + struct input *input = data; + struct window *window = input->pointer_focus; + + input->sx = x; + input->sy = y; + + if (window->data_handler) + window->data_handler(window, input, time, x, y, + input->drag_offer->types.data, + window->user_data); +} + +static void +data_device_drop(void *data, struct wl_data_device *data_device) +{ + struct input *input = data; + struct window *window = input->pointer_focus; + + if (window->drop_handler) + window->drop_handler(window, input, + input->sx, input->sy, window->user_data); +} + +static void +data_device_selection(void *data, + struct wl_data_device *wl_data_device, + struct wl_data_offer *offer) +{ + struct input *input = data; + char **p; + + if (input->selection_offer) + data_offer_destroy(input->selection_offer); + + input->selection_offer = wl_data_offer_get_user_data(offer); + p = wl_array_add(&input->selection_offer->types, sizeof *p); + *p = NULL; +} + +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 +}; + +struct wl_data_device * +input_get_data_device(struct input *input) +{ + return input->data_device; } void -window_move(struct window *window, struct input *input, uint32_t time) +input_set_selection(struct input *input, + struct wl_data_source *source, uint32_t time) { - if (window->display->shell) - wl_shell_move(window->display->shell, - window->surface, input->input_device, time); + wl_data_device_set_selection(input->data_device, source, time); +} + +void +input_accept(struct input *input, uint32_t time, const char *type) +{ + wl_data_offer_accept(input->drag_offer->offer, time, type); +} + +static void +offer_io_func(struct task *task, uint32_t events) +{ + struct data_offer *offer = + container_of(task, struct data_offer, 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); + + if (len == 0) { + close(offer->fd); + data_offer_destroy(offer); + } +} + +static void +data_offer_receive_data(struct data_offer *offer, const char *mime_type, + data_func_t func, void *user_data) +{ + int p[2]; + + pipe2(p, O_CLOEXEC); + 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; + + display_watch_fd(offer->input->display, + offer->fd, EPOLLIN, &offer->io_task); } void -window_activate_drag(struct wl_drag *drag, struct window *window, - struct input *input, uint32_t time) +input_receive_drag_data(struct input *input, const char *mime_type, + data_func_t func, void *data) +{ + data_offer_receive_data(input->drag_offer, mime_type, func, data); + input->drag_offer->x = input->sx; + input->drag_offer->y = input->sy; +} + +int +input_receive_selection_data(struct input *input, const char *mime_type, + data_func_t func, void *data) { - wl_drag_activate(drag, window->surface, input->input_device, time); + char **p; + + if (input->selection_offer == NULL) + return -1; + + 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); + return 0; +} + +void +window_move(struct window *window, struct input *input, uint32_t time) +{ + if (window->display->shell) + wl_shell_move(window->display->shell, + window->surface, input->input_device, time); } static void @@ -1666,6 +1891,18 @@ window_set_item_focus_handler(struct window *window, } void +window_set_data_handler(struct window *window, window_data_handler_t handler) +{ + window->data_handler = handler; +} + +void +window_set_drop_handler(struct window *window, window_drop_handler_t handler) +{ + window->drop_handler = handler; +} + +void window_set_transparent(struct window *window, int transparent) { window->transparent = transparent; @@ -1834,113 +2071,12 @@ display_add_input(struct display *d, uint32_t id) wl_input_device_add_listener(input->input_device, &input_device_listener, input); wl_input_device_set_user_data(input->input_device, input); -} -struct selection_offer { - struct display *display; - struct wl_selection_offer *offer; - struct wl_array types; - struct input *input; -}; - -int -input_offers_mime_type(struct input *input, const char *type) -{ - struct selection_offer *offer = input->offer; - char **p, **end; - - if (offer == NULL) - return 0; - - end = offer->types.data + offer->types.size; - for (p = offer->types.data; p < end; p++) - if (strcmp(*p, type) == 0) - return 1; - - return 0; -} - -void -input_receive_mime_type(struct input *input, const char *type, int fd) -{ - struct selection_offer *offer = input->offer; - - /* FIXME: A number of things can go wrong here: the object may - * not be the current selection offer any more (which could - * still work, but the source may have gone away or just - * destroyed its wl_selection) or the offer may not have the - * requested type after all (programmer/client error, - * typically) */ - wl_selection_offer_receive(offer->offer, type, fd); -} - -static void -selection_offer_offer(void *data, - struct wl_selection_offer *selection_offer, - const char *type) -{ - struct selection_offer *offer = data; - - char **p; - - p = wl_array_add(&offer->types, sizeof *p); - if (p) - *p = strdup(type); -}; - -static void -selection_offer_keyboard_focus(void *data, - struct wl_selection_offer *selection_offer, - struct wl_input_device *input_device) -{ - struct selection_offer *offer = data; - struct input *input; - char **p, **end; - - if (input_device == NULL) { - printf("selection offer retracted %p\n", selection_offer); - input = offer->input; - input->offer = NULL; - wl_selection_offer_destroy(selection_offer); - wl_array_release(&offer->types); - free(offer); - return; - } - - input = wl_input_device_get_user_data(input_device); - printf("new selection offer %p:", selection_offer); - - offer->input = input; - input->offer = offer; - end = offer->types.data + offer->types.size; - for (p = offer->types.data; p < end; p++) - printf(" %s", *p); - - printf("\n"); -} - -struct wl_selection_offer_listener selection_offer_listener = { - selection_offer_offer, - selection_offer_keyboard_focus -}; - -static void -add_selection_offer(struct display *d, uint32_t id) -{ - struct selection_offer *offer; - - offer = malloc(sizeof *offer); - if (offer == NULL) - return; - - offer->offer = - wl_display_bind(d->display, id, &wl_selection_offer_interface); - offer->display = d; - wl_array_init(&offer->types); - offer->input = NULL; - - wl_selection_offer_add_listener(offer->offer, - &selection_offer_listener, offer); + input->data_device = + wl_data_device_manager_get_data_device(d->data_device_manager, + input->input_device); + wl_data_device_add_listener(input->data_device, + &data_device_listener, input); } static void @@ -1962,8 +2098,10 @@ display_handle_global(struct wl_display *display, uint32_t id, wl_shell_add_listener(d->shell, &shell_listener, d); } else if (strcmp(interface, "wl_shm") == 0) { d->shm = wl_display_bind(display, id, &wl_shm_interface); - } else if (strcmp(interface, "wl_selection_offer") == 0) { - add_selection_offer(d, id); + } else if (strcmp(interface, "wl_data_device_manager") == 0) { + d->data_device_manager = + wl_display_bind(display, id, + &wl_data_device_manager_interface); } } @@ -2215,6 +2353,12 @@ display_get_egl_display(struct display *d) return d->dpy; } +struct wl_data_source * +display_create_data_source(struct display *display) +{ + return wl_data_device_manager_create_data_source(display->data_device_manager); +} + EGLConfig display_get_rgb_egl_config(struct display *d) { diff --git a/clients/window.h b/clients/window.h index bad1e60..d285bb1 100644 --- a/clients/window.h +++ b/clients/window.h @@ -57,6 +57,9 @@ display_get_compositor(struct display *display); struct wl_shell * display_get_shell(struct display *display); +struct wl_data_source * +display_create_data_source(struct display *display); + #ifdef EGL_NO_DISPLAY EGLDisplay display_get_egl_display(struct display *d); @@ -100,11 +103,6 @@ display_get_pointer_surface(struct display *display, int pointer, int *hotspot_x, int *hotspot_y); void -display_add_drag_listener(struct display *display, - const struct wl_drag_listener *drag_listener, - void *data); - -void display_defer(struct display *display, struct task *task); void @@ -157,6 +155,16 @@ typedef int (*window_motion_handler_t)(struct window *window, int32_t x, int32_t y, int32_t sx, int32_t sy, void *data); +typedef void (*window_data_handler_t)(struct window *window, + struct input *input, uint32_t time, + int32_t x, int32_t 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_item_focus_handler_t)(struct window *window, struct item *focus, void *data); @@ -174,6 +182,9 @@ window_add_item(struct window *window, void *data); typedef void (*item_func_t)(struct item *item, void *data); +typedef void (*data_func_t)(void *data, size_t len, + int32_t x, int32_t y, void *user_data); + void window_for_each_item(struct window *window, item_func_t func, void *data); @@ -286,18 +297,19 @@ window_set_item_focus_handler(struct window *window, window_item_focus_handler_t handler); void +window_set_data_handler(struct window *window, + window_data_handler_t handler); + +void +window_set_drop_handler(struct window *window, + window_drop_handler_t handler); + +void window_set_title(struct window *window, const char *title); const char * window_get_title(struct window *window); -struct wl_drag * -window_create_drag(struct window *window); - -void -window_activate_drag(struct wl_drag *drag, struct window *window, - struct input *input, uint32_t time); - void item_get_allocation(struct item *item, struct rectangle *allocation); @@ -309,6 +321,9 @@ void * item_get_user_data(struct item *item); void +input_set_pointer_image(struct input *input, uint32_t time, int pointer); + +void input_get_position(struct input *input, int32_t *x, int32_t *y); uint32_t @@ -317,10 +332,24 @@ input_get_modifiers(struct input *input); struct wl_input_device * input_get_input_device(struct input *input); -int -input_offers_mime_type(struct input *input, const char *type); +struct wl_data_device * +input_get_data_device(struct input *input); + void -input_receive_mime_type(struct input *input, const char *type, int fd); +input_set_selection(struct input *input, + struct wl_data_source *source, uint32_t time); + +void +input_accept(struct input *input, uint32_t time, const char *type); + + +void +input_receive_drag_data(struct input *input, const char *mime_type, + data_func_t func, void *user_data); + +int +input_receive_selection_data(struct input *input, const char *mime_type, + data_func_t func, void *data); enum { CONFIG_KEY_INTEGER, |