diff --git a/include/labwc.h b/include/labwc.h index 10a8e58a..97be5dfc 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -473,8 +473,9 @@ struct view *desktop_view_at_cursor(struct server *server); * cursor_rebase - set cursor icon for and send motion-event to surface below it * @seat - current seat * @time_msec - time now + * @force - disable check for skipping already focused surface */ -void cursor_rebase(struct seat *seat, uint32_t time_msec); +void cursor_rebase(struct seat *seat, uint32_t time_msec, bool force); /** * cursor_set - set cursor icon diff --git a/src/cursor.c b/src/cursor.c index 47d4b58e..b6aaa577 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -24,7 +24,7 @@ is_surface(enum ssd_part_type view_area) } void -cursor_rebase(struct seat *seat, uint32_t time_msec) +cursor_rebase(struct seat *seat, uint32_t time_msec, bool force) { double sx, sy; struct wlr_scene_node *node; @@ -38,6 +38,20 @@ cursor_rebase(struct seat *seat, uint32_t time_msec) } if (surface) { + if (!force && surface == seat->seat->pointer_state.focused_surface) { + /* + * Usually we prevent re-entering an already focued surface + * because it sends useless leave and enter events. + * + * They may also seriously confuse clients if sent between + * connected events like a double click (#258) or fast scroll + * events caused by a touchpad (#225). + * + * If we just want to update the cursor image though + * the @force argument may be used to allow re-entering. + */ + return; + } wlr_seat_pointer_notify_clear_focus(seat->seat); wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); wlr_seat_pointer_notify_motion(seat->seat, time_msec, sx, sy); @@ -195,15 +209,6 @@ process_cursor_motion(struct server *server, uint32_t time) } else if (server->input_mode == LAB_INPUT_STATE_RESIZE) { process_cursor_resize(server, time); return; - } else if (server->seat.active_view && !server->seat.drag_icon) { - /* Button has been pressed while over a view surface */ - struct view *view = server->seat.active_view; - double sx = server->seat.cursor->x - view->x; - double sy = server->seat.cursor->y - view->y; - sx = sx < 0 ? 0 : (sx > view->w ? view->w : sx); - sy = sy < 0 ? 0 : (sy > view->h ? view->h : sy); - wlr_seat_pointer_notify_motion(server->seat.seat, time, sx, sy); - return; } /* Otherwise, find view under the pointer and send the event along */ @@ -292,7 +297,21 @@ process_cursor_motion(struct server *server, uint32_t time) hover->node = NULL; } - if (surface && + if (server->seat.active_view && !server->seat.drag_icon) { + /* + * Button has been pressed while over a view surface + * and is still held down. Just send the adjusted motion + * events to the focused surface so we can keep scrolling + * or selecting text even if the cursor moves outside of + * the surface. + */ + view = server->seat.active_view; + double sx = server->seat.cursor->x - view->x; + double sy = server->seat.cursor->y - view->y; + sx = sx < 0 ? 0 : (sx > view->w ? view->w : sx); + sy = sy < 0 ? 0 : (sy > view->h ? view->h : sy); + wlr_seat_pointer_notify_motion(server->seat.seat, time, sx, sy); + } else if (surface && !input_inhibit_blocks_surface(&server->seat, surface->resource)) { bool focus_changed = wlr_seat->pointer_state.focused_surface != surface; @@ -316,6 +335,9 @@ process_cursor_motion(struct server *server, uint32_t time) /* * Clear pointer focus so future button events and such are not * sent to the last client to have the cursor over it. + * + * Except if we started pressing a button on the last client and + * are not currently in drag and drop mode. */ wlr_seat_pointer_clear_focus(wlr_seat); } @@ -332,7 +354,8 @@ cursor_update_focus(struct server *server) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - cursor_rebase(&server->seat, msec(&now)); + /* Focus surface under cursor if it isn't already focused */ + cursor_rebase(&server->seat, msec(&now), false); } void @@ -693,7 +716,9 @@ cursor_button(struct wl_listener *listener, void *data) server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; server->grabbed_view = NULL; } - cursor_rebase(&server->seat, event->time_msec); + + /* Focus surface under cursor and force updating the cursor icon */ + cursor_rebase(&server->seat, event->time_msec, true); return; } goto mousebindings;