diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ea6b8aa..caf1a73d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,6 +123,8 @@ means foot can be PGO:d in e.g. sandboxed build scripts. See (https://codeberg.org/dnkl/foot/issues/233). * `\E[s`+`\E[u` (save/restore cursor) now saves and restores attributes and charset configuration, just like `\E7`+`\E8`. +* Report mouse motion events to the client application also while + dragging the cursor outside the grid. ### Security diff --git a/input.c b/input.c index d457fb4c..bee0bbbd 100644 --- a/input.c +++ b/input.c @@ -1250,7 +1250,7 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, /* Reset mouse state */ seat->mouse.x = seat->mouse.y = 0; seat->mouse.col = seat->mouse.row = 0; - seat->mouse.button = seat->mouse.last_button = seat->mouse.count = 0; + seat->mouse.button = seat->mouse.last_button = seat->mouse.button_for_motion_events = seat->mouse.count = 0; seat->mouse.consumed = false; memset(&seat->mouse.last_time, 0, sizeof(seat->mouse.last_time)); seat->mouse.axis_aggregated = 0.0; @@ -1383,6 +1383,16 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, selection_row = seat->mouse.row; } + /* + * If client is receiving events (because the button was + * pressed while the cursor was inside the grid area), then + * make sure it receives valid coordinates. + */ + if (seat->mouse.button_for_motion_events > 0) { + seat->mouse.col = selection_col; + seat->mouse.row = selection_row; + } + assert(seat->mouse.col == -1 || (seat->mouse.col >= 0 && seat->mouse.col < term->cols)); assert(seat->mouse.row == -1 || (seat->mouse.row >= 0 && seat->mouse.row < term->rows)); @@ -1440,13 +1450,18 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, /* Send mouse event to client application */ if (!seat->mouse.consumed && !term_mouse_grabbed(term, seat) && - cursor_is_on_new_cell && cursor_is_on_grid) + cursor_is_on_new_cell && + (seat->mouse.button_for_motion_events > 0 || + (seat->mouse.button == 0 && cursor_is_on_grid))) { assert(seat->mouse.col < term->cols); assert(seat->mouse.row < term->rows); term_mouse_motion( - term, seat->mouse.button, seat->mouse.row, seat->mouse.col, + term, + (seat->mouse.button_for_motion_events > 0 + ? seat->mouse.button_for_motion_events : seat->mouse.button), + seat->mouse.row, seat->mouse.col, seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); } break; @@ -1702,6 +1717,9 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, term_mouse_down( term, button, seat->mouse.row, seat->mouse.col, seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + + if (seat->mouse.button_for_motion_events == 0) + seat->mouse.button_for_motion_events = button; } break; } @@ -1711,11 +1729,15 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, if (!seat->mouse.consumed && !term_mouse_grabbed(term, seat) && - cursor_is_on_grid) + ((cursor_is_on_grid && seat->mouse.button_for_motion_events > 0) || + seat->mouse.button_for_motion_events == button)) { term_mouse_up( term, button, seat->mouse.row, seat->mouse.col, seat->kbd.shift, seat->kbd.alt, seat->kbd.ctrl); + + if (seat->mouse.button_for_motion_events == button) + seat->mouse.button_for_motion_events = 0; } seat->mouse.consumed = false; diff --git a/wayland.h b/wayland.h index ac61c6ff..16678496 100644 --- a/wayland.h +++ b/wayland.h @@ -202,6 +202,18 @@ struct seat { int col; int row; int button; + + /* + * Button to send in motion events to the client. This is + * always the *first* button pressed on the grid. If multiple + * buttons are pressed, the first button is still the one used + * in motion events. + * + * A non-zero value of this *also* indicates that the client + * should receive events even if the pointer is outside the + * grid. + */ + int button_for_motion_events; bool consumed; /* True if a button press was consumed - i.e. if a binding claimed it */ int count;