diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 85d661a77..aa0084216 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -94,18 +94,7 @@ struct wlr_drag_icon { void *data; }; -enum wlr_drag_grab_type { - WLR_DRAG_GRAB_KEYBOARD, - WLR_DRAG_GRAB_KEYBOARD_POINTER, - WLR_DRAG_GRAB_KEYBOARD_TOUCH, -}; - struct wlr_drag { - enum wlr_drag_grab_type grab_type; - struct wlr_seat_keyboard_grab keyboard_grab; - struct wlr_seat_pointer_grab pointer_grab; - struct wlr_seat_touch_grab touch_grab; - struct wlr_seat *seat; struct wlr_seat_client *seat_client; struct wlr_seat_client *focus_client; @@ -181,25 +170,22 @@ void wlr_seat_request_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, struct wlr_surface *origin, uint32_t serial); /** - * Starts a drag on the seat. This starts an implicit keyboard grab, but doesn't - * start a pointer or a touch grab. + * Starts a drag on the seat. */ void wlr_seat_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, uint32_t serial); -/** - * Starts a pointer drag on the seat. This starts implicit keyboard and pointer - * grabs. - */ -void wlr_seat_start_pointer_drag(struct wlr_seat *seat, struct wlr_drag *drag, - uint32_t serial); +void wlr_seat_drag_enter(struct wlr_seat *seat, struct wlr_surface *surface, + double sx, double sy); -/** - * Starts a touch drag on the seat. This starts implicit keyboard and touch - * grabs. - */ -void wlr_seat_start_touch_drag(struct wlr_seat *seat, struct wlr_drag *drag, - uint32_t serial, struct wlr_touch_point *point); +void wlr_seat_drag_clear_focus(struct wlr_seat *seat); + +void wlr_seat_drag_send_motion(struct wlr_seat *seat, uint32_t time_msec, + double sx, double sy); + +void wlr_seat_drag_drop_and_destroy(struct wlr_seat *seat, uint32_t time_msec); + +void wlr_seat_drag_destroy(struct wlr_seat *seat); /** * Initializes the data source with the provided implementation. diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index c6e9e59ec..e8a640b13 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -19,93 +19,6 @@ static void drag_handle_seat_client_destroy(struct wl_listener *listener, wl_list_remove(&drag->seat_client_destroy.link); } -static void drag_set_focus(struct wlr_drag *drag, - struct wlr_surface *surface, double sx, double sy) { - if (drag->focus == surface) { - return; - } - - if (drag->focus_client) { - wl_list_remove(&drag->seat_client_destroy.link); - - // If we're switching focus to another client, we want to destroy all - // offers without destroying the source. If the drag operation ends, we - // want to keep the offer around for the data transfer. - struct wlr_data_offer *offer, *tmp; - wl_list_for_each_safe(offer, tmp, - &drag->focus_client->seat->drag_offers, link) { - struct wl_client *client = wl_resource_get_client(offer->resource); - if (!drag->dropped && offer->source == drag->source && - client == drag->focus_client->client) { - offer->source = NULL; - data_offer_destroy(offer); - } - } - - struct wl_resource *resource; - wl_resource_for_each(resource, &drag->focus_client->data_devices) { - wl_data_device_send_leave(resource); - } - - drag->focus_client = NULL; - drag->focus = NULL; - } - - if (!surface) { - goto out; - } - - if (!drag->source && drag->seat_client && - wl_resource_get_client(surface->resource) != - drag->seat_client->client) { - goto out; - } - - struct wlr_seat_client *focus_client = wlr_seat_client_for_wl_client( - drag->seat, wl_resource_get_client(surface->resource)); - if (!focus_client) { - goto out; - } - - if (drag->source != NULL) { - drag->source->accepted = false; - - uint32_t serial = - wl_display_next_serial(drag->seat->display); - - struct wl_resource *device_resource; - wl_resource_for_each(device_resource, &focus_client->data_devices) { - struct wlr_data_offer *offer = data_offer_create(device_resource, - drag->source, WLR_DATA_OFFER_DRAG); - if (offer == NULL) { - wl_resource_post_no_memory(device_resource); - return; - } - - data_offer_update_action(offer); - - if (wl_resource_get_version(offer->resource) >= - WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) { - wl_data_offer_send_source_actions(offer->resource, - drag->source->actions); - } - - wl_data_device_send_enter(device_resource, serial, - surface->resource, - wl_fixed_from_double(sx), wl_fixed_from_double(sy), - offer->resource); - } - } - - drag->focus = surface; - drag->focus_client = focus_client; - drag->seat_client_destroy.notify = drag_handle_seat_client_destroy; - wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy); - -out: - wl_signal_emit_mutable(&drag->events.focus, drag); -} - static void drag_icon_destroy(struct wlr_drag_icon *icon) { icon->drag->icon = NULL; wl_list_remove(&icon->surface_destroy.link); @@ -114,37 +27,15 @@ static void drag_icon_destroy(struct wlr_drag_icon *icon) { } static void drag_destroy(struct wlr_drag *drag) { - if (drag->cancelling) { - return; - } - drag->cancelling = true; - if (drag->started) { - wlr_seat_keyboard_end_grab(drag->seat); - switch (drag->grab_type) { - case WLR_DRAG_GRAB_KEYBOARD: - break; - case WLR_DRAG_GRAB_KEYBOARD_POINTER: - wlr_seat_pointer_end_grab(drag->seat); - break; - case WLR_DRAG_GRAB_KEYBOARD_TOUCH: - wlr_seat_touch_end_grab(drag->seat); - break; - } - } - - if (drag->started) { - drag_set_focus(drag, NULL, 0, 0); + wlr_seat_drag_clear_focus(drag->seat); assert(drag->seat->drag == drag); drag->seat->drag = NULL; } - // We issue destroy after ending the grab to allow focus changes. - // Furthermore, we wait until after clearing the drag focus in order - // to ensure that the wl_data_device.leave is sent before emitting the - // signal. This allows e.g. wl_pointer.enter to be sent in the destroy - // signal handler. + // We wait until after clearing the drag focus to ensure that + // wl_data_device.leave is sent before emitting the signal. wl_signal_emit_mutable(&drag->events.destroy, drag); if (drag->source) { @@ -157,192 +48,6 @@ static void drag_destroy(struct wlr_drag *drag) { free(drag); } -static void drag_handle_pointer_enter(struct wlr_seat_pointer_grab *grab, - struct wlr_surface *surface, double sx, double sy) { - struct wlr_drag *drag = grab->data; - drag_set_focus(drag, surface, sx, sy); -} - -static void drag_handle_pointer_clear_focus(struct wlr_seat_pointer_grab *grab) { - struct wlr_drag *drag = grab->data; - drag_set_focus(drag, NULL, 0, 0); -} - -static void drag_handle_pointer_motion(struct wlr_seat_pointer_grab *grab, - uint32_t time, double sx, double sy) { - struct wlr_drag *drag = grab->data; - if (drag->focus != NULL && drag->focus_client != NULL) { - struct wl_resource *resource; - wl_resource_for_each(resource, &drag->focus_client->data_devices) { - wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx), - wl_fixed_from_double(sy)); - } - - struct wlr_drag_motion_event event = { - .drag = drag, - .time = time, - .sx = sx, - .sy = sy, - }; - wl_signal_emit_mutable(&drag->events.motion, &event); - } -} - -static void drag_drop(struct wlr_drag *drag, uint32_t time) { - assert(drag->focus_client); - - drag->dropped = true; - - struct wl_resource *resource; - wl_resource_for_each(resource, &drag->focus_client->data_devices) { - wl_data_device_send_drop(resource); - } - if (drag->source) { - wlr_data_source_dnd_drop(drag->source); - } - - struct wlr_drag_drop_event event = { - .drag = drag, - .time = time, - }; - wl_signal_emit_mutable(&drag->events.drop, &event); -} - -static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab, - uint32_t time, uint32_t button, uint32_t state) { - struct wlr_drag *drag = grab->data; - - if (drag->source && - grab->seat->pointer_state.grab_button == button && - state == WL_POINTER_BUTTON_STATE_RELEASED) { - if (drag->focus_client && drag->source->current_dnd_action && - drag->source->accepted) { - drag_drop(drag, time); - } else if (drag->source->impl->dnd_finish) { - // This will end the grab and free `drag` - wlr_data_source_destroy(drag->source); - return 0; - } - } - - if (grab->seat->pointer_state.button_count == 0 && - state == WL_POINTER_BUTTON_STATE_RELEASED) { - drag_destroy(drag); - } - - return 0; -} - -static void drag_handle_pointer_axis(struct wlr_seat_pointer_grab *grab, - uint32_t time, enum wlr_axis_orientation orientation, double value, - int32_t value_discrete, enum wlr_axis_source source) { - // This space is intentionally left blank -} - -static void drag_handle_pointer_cancel(struct wlr_seat_pointer_grab *grab) { - struct wlr_drag *drag = grab->data; - drag_destroy(drag); -} - -static const struct wlr_pointer_grab_interface - data_device_pointer_drag_interface = { - .enter = drag_handle_pointer_enter, - .clear_focus = drag_handle_pointer_clear_focus, - .motion = drag_handle_pointer_motion, - .button = drag_handle_pointer_button, - .axis = drag_handle_pointer_axis, - .cancel = drag_handle_pointer_cancel, -}; - -static uint32_t drag_handle_touch_down(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - // eat the event - return 0; -} - -static void drag_handle_touch_up(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - struct wlr_drag *drag = grab->data; - if (drag->grab_touch_id != point->touch_id) { - return; - } - - if (drag->focus_client) { - drag_drop(drag, time); - } - - drag_destroy(drag); -} - -static void drag_handle_touch_motion(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - struct wlr_drag *drag = grab->data; - if (drag->focus && drag->focus_client) { - struct wl_resource *resource; - wl_resource_for_each(resource, &drag->focus_client->data_devices) { - wl_data_device_send_motion(resource, time, - wl_fixed_from_double(point->sx), - wl_fixed_from_double(point->sy)); - } - } -} - -static void drag_handle_touch_enter(struct wlr_seat_touch_grab *grab, - uint32_t time, struct wlr_touch_point *point) { - struct wlr_drag *drag = grab->data; - drag_set_focus(drag, point->focus_surface, point->sx, point->sy); -} - -static void drag_handle_touch_cancel(struct wlr_seat_touch_grab *grab) { - struct wlr_drag *drag = grab->data; - drag_destroy(drag); -} - -static const struct wlr_touch_grab_interface - data_device_touch_drag_interface = { - .down = drag_handle_touch_down, - .up = drag_handle_touch_up, - .motion = drag_handle_touch_motion, - .enter = drag_handle_touch_enter, - .cancel = drag_handle_touch_cancel, -}; - -static void drag_handle_keyboard_enter(struct wlr_seat_keyboard_grab *grab, - struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes, - const struct wlr_keyboard_modifiers *modifiers) { - // nothing has keyboard focus during drags -} - -static void drag_handle_keyboard_clear_focus(struct wlr_seat_keyboard_grab *grab) { - // nothing has keyboard focus during drags -} - -static void drag_handle_keyboard_key(struct wlr_seat_keyboard_grab *grab, - uint32_t time, uint32_t key, uint32_t state) { - // no keyboard input during drags -} - -static void drag_handle_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab, - const struct wlr_keyboard_modifiers *modifiers) { - //struct wlr_keyboard *keyboard = grab->seat->keyboard_state.keyboard; - // TODO change the dnd action based on what modifier is pressed on the - // keyboard -} - -static void drag_handle_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) { - struct wlr_drag *drag = grab->data; - drag_destroy(drag); -} - -static const struct wlr_keyboard_grab_interface - data_device_keyboard_drag_interface = { - .enter = drag_handle_keyboard_enter, - .clear_focus = drag_handle_keyboard_clear_focus, - .key = drag_handle_keyboard_key, - .modifiers = drag_handle_keyboard_modifiers, - .cancel = drag_handle_keyboard_cancel, -}; - static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) { struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy); drag->icon = NULL; @@ -430,15 +135,6 @@ struct wlr_drag *wlr_drag_create(struct wlr_seat_client *seat_client, wl_signal_add(&source->events.destroy, &drag->source_destroy); } - drag->pointer_grab.data = drag; - drag->pointer_grab.interface = &data_device_pointer_drag_interface; - - drag->touch_grab.data = drag; - drag->touch_grab.interface = &data_device_touch_drag_interface; - - drag->keyboard_grab.data = drag; - drag->keyboard_grab.interface = &data_device_keyboard_drag_interface; - return drag; } @@ -474,8 +170,6 @@ void wlr_seat_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, assert(!drag->started); drag->started = true; - wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab); - seat->drag = drag; seat->drag_serial = serial; @@ -491,24 +185,156 @@ void wlr_seat_start_drag(struct wlr_seat *seat, struct wlr_drag *drag, wl_signal_emit_mutable(&seat->events.start_drag, drag); } -void wlr_seat_start_pointer_drag(struct wlr_seat *seat, struct wlr_drag *drag, - uint32_t serial) { - drag->grab_type = WLR_DRAG_GRAB_KEYBOARD_POINTER; +void wlr_seat_drag_enter(struct wlr_seat *seat, struct wlr_surface *surface, + double sx, double sy) { + struct wlr_drag *drag = seat->drag; + assert(drag != NULL); - wlr_seat_pointer_clear_focus(seat); - wlr_seat_pointer_start_grab(seat, &drag->pointer_grab); + if (drag->focus == surface) { + return; + } - wlr_seat_start_drag(seat, drag, serial); + if (drag->focus_client) { + wl_list_remove(&drag->seat_client_destroy.link); + + // If we're switching focus to another client, we want to destroy all + // offers without destroying the source. If the drag operation ends, we + // want to keep the offer around for the data transfer. + struct wlr_data_offer *offer, *tmp; + wl_list_for_each_safe(offer, tmp, + &drag->focus_client->seat->drag_offers, link) { + struct wl_client *client = wl_resource_get_client(offer->resource); + if (!drag->dropped && offer->source == drag->source && + client == drag->focus_client->client) { + offer->source = NULL; + data_offer_destroy(offer); + } + } + + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_leave(resource); + } + + drag->focus_client = NULL; + drag->focus = NULL; + } + + if (!surface) { + goto out; + } + + if (!drag->source && drag->seat_client && + wl_resource_get_client(surface->resource) != + drag->seat_client->client) { + goto out; + } + + struct wlr_seat_client *focus_client = wlr_seat_client_for_wl_client( + drag->seat, wl_resource_get_client(surface->resource)); + if (!focus_client) { + goto out; + } + + if (drag->source != NULL) { + drag->source->accepted = false; + + uint32_t serial = + wl_display_next_serial(drag->seat->display); + + struct wl_resource *device_resource; + wl_resource_for_each(device_resource, &focus_client->data_devices) { + struct wlr_data_offer *offer = data_offer_create(device_resource, + drag->source, WLR_DATA_OFFER_DRAG); + if (offer == NULL) { + wl_resource_post_no_memory(device_resource); + return; + } + + data_offer_update_action(offer); + + if (wl_resource_get_version(offer->resource) >= + WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) { + wl_data_offer_send_source_actions(offer->resource, + drag->source->actions); + } + + wl_data_device_send_enter(device_resource, serial, + surface->resource, + wl_fixed_from_double(sx), wl_fixed_from_double(sy), + offer->resource); + } + } + + drag->focus = surface; + drag->focus_client = focus_client; + drag->seat_client_destroy.notify = drag_handle_seat_client_destroy; + wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy); + +out: + wl_signal_emit_mutable(&drag->events.focus, drag); } -void wlr_seat_start_touch_drag(struct wlr_seat *seat, struct wlr_drag *drag, - uint32_t serial, struct wlr_touch_point *point) { - drag->grab_type = WLR_DRAG_GRAB_KEYBOARD_TOUCH; - drag->grab_touch_id = seat->touch_state.grab_id; - drag->touch_id = point->touch_id; - - wlr_seat_touch_start_grab(seat, &drag->touch_grab); - drag_set_focus(drag, point->surface, point->sx, point->sy); - - wlr_seat_start_drag(seat, drag, serial); +void wlr_seat_drag_clear_focus(struct wlr_seat *seat) { + wlr_seat_drag_enter(seat, NULL, 0, 0); +} + +void wlr_seat_drag_send_motion(struct wlr_seat *seat, uint32_t time_msec, + double sx, double sy) { + struct wlr_drag *drag = seat->drag; + assert(drag != NULL); + + if (drag->focus != NULL && drag->focus_client != NULL) { + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_motion(resource, time_msec, + wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + } + + struct wlr_drag_motion_event event = { + .drag = drag, + .time = time_msec, + .sx = sx, + .sy = sy, + }; + wl_signal_emit_mutable(&drag->events.motion, &event); + } +} + +void wlr_seat_drag_drop_and_destroy(struct wlr_seat *seat, uint32_t time_msec) { + struct wlr_drag *drag = seat->drag; + assert(drag != NULL); + + if (drag->source != NULL) { + if (drag->focus_client != NULL && + drag->source->current_dnd_action != WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE && + drag->source->accepted) { + drag->dropped = true; + + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_drop(resource); + } + wlr_data_source_dnd_drop(drag->source); + + struct wlr_drag_drop_event event = { + .drag = drag, + .time = time_msec, + }; + wl_signal_emit_mutable(&drag->events.drop, &event); + } else if (drag->source->impl->dnd_finish != NULL) { + // This will call drag_destroy() + wlr_data_source_destroy(drag->source); + return; + } + } + + drag_destroy(drag); +} + +void wlr_seat_drag_destroy(struct wlr_seat *seat) { + struct wlr_drag *drag = seat->drag; + assert(drag != NULL); + + drag_destroy(drag); }