diff --git a/TODO b/TODO index 7c588988..3fe9b990 100644 --- a/TODO +++ b/TODO @@ -16,26 +16,6 @@ Core wayland protocol - DnD issues: - How to roboustly handle failing drag, ie the case where an - application gets a button event, tries to activate a drag, but when - the server gets the drag request, the button has already been - released and the grab is no longer active. What's the concern: - - - Application may set a drag cursor that doesn't revert back, - since a failed drag doesn't result in a pointer_focus event to - give focus back to the surface. We could just do that: if the - pointer_focus is the same surface as we tried to start a grab - for, just remove and give back pointer_focus. - - Alternatively, set drag cursors only in response to drag events, - like drag focus. But drag_focus and drag_motion are sent to the - drag target, so the source surface won't always get those. We - may also end up setting the cursor after the drag ends, but in - this case the drag started and ended and we'll get a - pointer_focus event, which will make the application reset the - pointer image. Could introduce a drag start event that - indicates that the drag active. - How to handle drop decline (accept with type=NULL) - Targets must send a NULL type in accept if they don't accept a diff --git a/clients/dnd.c b/clients/dnd.c index 0557ed9b..3df1202d 100644 --- a/clients/dnd.c +++ b/clients/dnd.c @@ -44,6 +44,9 @@ struct dnd { struct display *display; uint32_t key; struct item *items[16]; + + struct wl_buffer *buffer; + int hotspot_x, hotspot_y; }; struct item { @@ -249,7 +252,16 @@ static void drag_target(void *data, struct wl_drag *drag, const char *mime_type) { + struct dnd *dnd = data; + struct input *input; + struct wl_input_device *device; + fprintf(stderr, "target %s\n", mime_type); + + input = wl_drag_get_user_data(drag); + device = input_get_input_device(input); + wl_input_device_attach(device, dnd->buffer, + dnd->hotspot_x, dnd->hotspot_y); } static void @@ -269,7 +281,7 @@ static void drag_data(void *data, struct wl_drag *drag, struct wl_array *contents) { - fprintf(stderr, "drag drop, data %s\n", contents->data); + fprintf(stderr, "drag drop, data %s\n", (char *) contents->data); } static const struct wl_drag_listener drag_listener = { @@ -291,7 +303,6 @@ dnd_button_handler(struct window *window, int32_t x, y, hotspot_x, hotspot_y, pointer_width, pointer_height; struct rectangle rectangle; struct item *item; - struct wl_buffer *buffer; cairo_surface_t *surface, *pointer; cairo_t *cr; @@ -334,12 +345,12 @@ dnd_button_handler(struct window *window, cairo_paint(cr); cairo_destroy(cr); - buffer = display_get_buffer_for_surface(dnd->display, - surface); - window_start_drag(window, input, time, - buffer, - pointer_width + x - item->x, - pointer_height + y - item->y); + dnd->buffer = display_get_buffer_for_surface(dnd->display, + surface); + dnd->hotspot_x = pointer_width + x - item->x; + dnd->hotspot_y = pointer_height + y - item->y; + + window_start_drag(window, input, time); /* FIXME: We leak the surface because we can't free it * until the server has referenced it. */ @@ -407,6 +418,8 @@ dnd_create(struct display *display) rectangle.height = 4 * (item_height + item_padding) + item_padding; window_set_child_size(dnd->window, &rectangle); + display_add_drag_listener(display, &drag_listener, dnd); + dnd_draw(dnd); return dnd; @@ -428,8 +441,6 @@ main(int argc, char *argv[]) d = display_create(&argc, &argv, option_entries); - display_add_drag_listener(d, &drag_listener, d); - dnd = dnd_create (d); display_run(d); diff --git a/clients/window.c b/clients/window.c index 2b88e092..7c2579d8 100644 --- a/clients/window.c +++ b/clients/window.c @@ -561,9 +561,10 @@ window_handle_motion(void *data, struct wl_input_device *input_device, set_pointer_image(input, pointer); } -static void window_handle_button(void *data, - struct wl_input_device *input_device, - uint32_t time, uint32_t button, uint32_t state) +static void +window_handle_button(void *data, + struct wl_input_device *input_device, + uint32_t time, uint32_t button, uint32_t state) { struct input *input = data; struct window *window = input->pointer_focus; @@ -717,6 +718,12 @@ input_get_position(struct input *input, int32_t *x, int32_t *y) *y = input->sy; } +struct wl_input_device * +input_get_input_device(struct input *input) +{ + return input->input_device; +} + void display_add_drag_listener(struct display *display, const struct wl_drag_listener *drag_listener, @@ -729,12 +736,11 @@ display_add_drag_listener(struct display *display, } void -window_start_drag(struct window *window, struct input *input, uint32_t time, - struct wl_buffer *buffer, int32_t x, int32_t y) +window_start_drag(struct window *window, struct input *input, uint32_t time) { cairo_device_flush (window->display->device); - wl_drag_prepare(input->drag, window->surface, time, buffer, x, y); + wl_drag_prepare(input->drag, window->surface, time); wl_drag_offer(input->drag, "text/plain"); wl_drag_activate(input->drag); } diff --git a/clients/window.h b/clients/window.h index 2c0b49b6..a1f58e92 100644 --- a/clients/window.h +++ b/clients/window.h @@ -188,10 +188,12 @@ window_set_frame_handler(struct window *window, window_frame_handler_t handler); void -window_start_drag(struct window *window, struct input *input, uint32_t time, - struct wl_buffer *buffer, int32_t x, int32_t y); +window_start_drag(struct window *window, struct input *input, uint32_t time); void input_get_position(struct input *input, int32_t *x, int32_t *y); +struct wl_input_device * +input_get_input_device(struct input *input); + #endif diff --git a/compositor.c b/compositor.c index 2155d423..09c77ca3 100644 --- a/compositor.c +++ b/compositor.c @@ -952,8 +952,11 @@ input_device_attach(struct wl_client *client, (struct wlsc_input_device *) device_base; struct wlsc_buffer *buffer = (struct wlsc_buffer *) buffer_base; - if (device->pointer_focus == NULL || - device->pointer_focus->base.client != client) + if (device->pointer_focus == NULL) + return; + if (device->pointer_focus->base.client != client && + !(&device->pointer_focus->base == &wl_grab_surface && + device->grab_surface->base.client == client)) return; if (buffer == NULL) { @@ -1052,8 +1055,7 @@ wl_drag_reset(struct wl_drag *drag) static void drag_prepare(struct wl_client *client, - struct wl_drag *drag, struct wl_surface *surface, uint32_t time, - struct wl_buffer *buffer, int32_t hotspot_x, int32_t hotspot_y) + struct wl_drag *drag, struct wl_surface *surface, uint32_t time) { struct wlsc_input_device *device = (struct wlsc_input_device *) drag->input_device; @@ -1065,9 +1067,6 @@ drag_prepare(struct wl_client *client, wl_drag_reset(drag); drag->source = surface; drag->time = time; - drag->buffer = buffer; - drag->hotspot_x = hotspot_x; - drag->hotspot_y = hotspot_y; } static void @@ -1112,8 +1111,6 @@ drag_activate(struct wl_client *client, wlsc_input_device_start_grab(device, drag->time, WLSC_DEVICE_GRAB_DRAG); - wlsc_input_device_attach(device, (struct wlsc_buffer *) drag->buffer, - drag->hotspot_x, drag->hotspot_y); surface = pick_surface(device, &sx, &sy); wl_drag_set_pointer_focus(&device->drag, surface, drag->time, diff --git a/protocol.xml b/protocol.xml index 9abeffa6..01d8a73e 100644 --- a/protocol.xml +++ b/protocol.xml @@ -102,9 +102,6 @@ grab started by the button click at time --> - - -