From c505ce30191441f6bdc47eae13cf1af83d2fab41 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 29 Jan 2019 22:40:10 +0100 Subject: [PATCH 1/4] data-device: fix use-after-free on drop --- types/data_device/wlr_drag.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index d6e93cb2..20c9b30e 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -174,7 +174,9 @@ static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab, }; wlr_signal_emit_safe(&drag->events.drop, &event); } else if (drag->source->impl->dnd_finish) { + // This will end the grab and free `drag` wlr_data_source_destroy(drag->source); + return 0; } } From d6de329d981f232ad47657d389a76b0da3cd217f Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 30 Jan 2019 10:54:57 +0100 Subject: [PATCH 2/4] seat: don't send motion if pointer hasn't moved --- include/wlr/types/wlr_seat.h | 1 + rootston/cursor.c | 17 ++++++++++------- rootston/input.c | 5 +++-- types/seat/wlr_seat_pointer.c | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 103fa24d..c81c2cec 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -135,6 +135,7 @@ struct wlr_seat_pointer_state { struct wlr_seat *seat; struct wlr_seat_client *focused_client; struct wlr_surface *focused_surface; + double sx, sy; struct wlr_seat_pointer_grab *grab; struct wlr_seat_pointer_grab *default_grab; diff --git a/rootston/cursor.c b/rootston/cursor.c index 8ae098de..838f5d78 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -101,8 +101,7 @@ static void seat_view_deco_button(struct roots_seat_view *view, double sx, } static void roots_passthrough_cursor(struct roots_cursor *cursor, - int64_t time) { - bool focus_changed; + uint32_t time) { double sx, sy; struct roots_view *view = NULL; struct roots_seat *seat = cursor->seat; @@ -146,11 +145,8 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, cursor->wlr_surface = surface; if (surface) { - focus_changed = (seat->seat->pointer_state.focused_surface != surface); wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); - if (!focus_changed && time > 0) { - wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy); - } + wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy); } else { wlr_seat_pointer_clear_focus(seat->seat); } @@ -161,8 +157,15 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, } } +static inline int64_t timespec_to_msec(const struct timespec *a) { + return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; +} + void roots_cursor_update_focus(struct roots_cursor *cursor) { - roots_passthrough_cursor(cursor, -1); + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + roots_passthrough_cursor(cursor, timespec_to_msec(&now)); } void roots_cursor_update_position(struct roots_cursor *cursor, diff --git a/rootston/input.c b/rootston/input.c index a863b919..757f1b35 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -136,10 +136,11 @@ static inline int64_t timespec_to_msec(const struct timespec *a) { } void input_update_cursor_focus(struct roots_input *input) { - struct roots_seat *seat; struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + struct roots_seat *seat; wl_list_for_each(seat, &input->seats, link) { - clock_gettime(CLOCK_MONOTONIC, &now); roots_cursor_update_position(seat->cursor, timespec_to_msec(&now)); } } diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 8776457d..31901716 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -187,6 +187,13 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, wlr_seat->pointer_state.focused_client = client; wlr_seat->pointer_state.focused_surface = surface; + if (surface != NULL) { + wlr_seat->pointer_state.sx = sx; + wlr_seat->pointer_state.sy = sy; + } else { + wlr_seat->pointer_state.sx = NAN; + wlr_seat->pointer_state.sy = NAN; + } struct wlr_seat_pointer_focus_change_event event = { .seat = wlr_seat, @@ -209,6 +216,10 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, return; } + if (wlr_seat->pointer_state.sx == sx && wlr_seat->pointer_state.sy == sy) { + return; + } + struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { if (wlr_seat_client_from_pointer_resource(resource) == NULL) { @@ -218,6 +229,9 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); } + + wlr_seat->pointer_state.sx = sx; + wlr_seat->pointer_state.sy = sy; } uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, From faa00a4a3362a8d7ea3942be50f95eb693fddb2e Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 30 Jan 2019 14:07:59 +0100 Subject: [PATCH 3/4] rootston: only allow one drag icon per seat --- include/rootston/seat.h | 3 +-- rootston/cursor.c | 5 ++--- rootston/output.c | 15 +++++++-------- rootston/seat.c | 8 +++++--- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/rootston/seat.h b/include/rootston/seat.h index 4667cd38..a91d8481 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -29,7 +29,7 @@ struct roots_seat { struct wl_list views; // roots_seat_view::link bool has_focus; - struct wl_list drag_icons; // roots_drag_icon::link + struct roots_drag_icon *drag_icon; // can be NULL struct wl_list keyboards; struct wl_list pointers; @@ -61,7 +61,6 @@ struct roots_seat_view { struct roots_drag_icon { struct roots_seat *seat; struct wlr_drag_icon *wlr_drag_icon; - struct wl_list link; double x, y; diff --git a/rootston/cursor.c b/rootston/cursor.c index 838f5d78..6e09c06e 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -151,9 +151,8 @@ static void roots_passthrough_cursor(struct roots_cursor *cursor, wlr_seat_pointer_clear_focus(seat->seat); } - struct roots_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &seat->drag_icons, link) { - roots_drag_icon_update_position(drag_icon); + if (seat->drag_icon != NULL) { + roots_drag_icon_update_position(seat->drag_icon); } } diff --git a/rootston/output.c b/rootston/output.c index df8328dd..3aad1c06 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -120,15 +120,14 @@ static void drag_icons_for_each_surface(struct roots_input *input, void *user_data) { struct roots_seat *seat; wl_list_for_each(seat, &input->seats, link) { - struct roots_drag_icon *drag_icon; - wl_list_for_each(drag_icon, &seat->drag_icons, link) { - if (!drag_icon->wlr_drag_icon->mapped) { - continue; - } - surface_for_each_surface(drag_icon->wlr_drag_icon->surface, - drag_icon->x, drag_icon->y, 0, layout_data, - iterator, user_data); + struct roots_drag_icon *drag_icon = seat->drag_icon; + if (drag_icon == NULL || !drag_icon->wlr_drag_icon->mapped) { + continue; } + + surface_for_each_surface(drag_icon->wlr_drag_icon->surface, + drag_icon->x, drag_icon->y, 0, layout_data, + iterator, user_data); } } diff --git a/rootston/seat.c b/rootston/seat.c index a6281f50..cd95472d 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -594,7 +594,9 @@ static void roots_drag_icon_handle_destroy(struct wl_listener *listener, wl_container_of(listener, icon, destroy); roots_drag_icon_damage_whole(icon); - wl_list_remove(&icon->link); + assert(icon->seat->drag_icon == icon); + icon->seat->drag_icon = NULL; + wl_list_remove(&icon->surface_commit.link); wl_list_remove(&icon->unmap.link); wl_list_remove(&icon->destroy.link); @@ -622,7 +624,8 @@ static void roots_seat_handle_new_drag_icon(struct wl_listener *listener, icon->destroy.notify = roots_drag_icon_handle_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); - wl_list_insert(&seat->drag_icons, &icon->link); + assert(seat->drag_icon == NULL); + seat->drag_icon = icon; roots_drag_icon_update_position(icon); } @@ -706,7 +709,6 @@ struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { wl_list_init(&seat->tablet_pads); wl_list_init(&seat->switches); wl_list_init(&seat->views); - wl_list_init(&seat->drag_icons); seat->input = input; From 29952dee19c030d2ae1034e0304de72a645b4444 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 30 Jan 2019 14:23:00 +0100 Subject: [PATCH 4/4] data-device: only allow one drag at a time --- types/data_device/wlr_drag.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 20c9b30e..9bd63d96 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -122,6 +122,9 @@ static void drag_end(struct wlr_drag *drag) { drag_icon_set_mapped(drag->icon, false); } + assert(drag->seat->drag == drag); + drag->seat->drag = NULL; + wlr_signal_emit_safe(&drag->events.destroy, drag); free(drag); } @@ -434,6 +437,13 @@ bool seat_client_start_drag(struct wlr_seat_client *client, return true; } + if (seat->drag != NULL) { + wlr_log(WLR_DEBUG, "Refusing to start drag, " + "another drag is already in progress"); + free(drag); + return true; + } + if (icon_surface) { int32_t touch_id = (point ? point->touch_id : 0); struct wlr_drag_icon *icon =