Merge branch 'scroll-up-down-while-selecting' into master

Closes #149
This commit is contained in:
Daniel Eklöf 2020-10-12 20:20:26 +02:00
commit d75e50230e
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
6 changed files with 164 additions and 1 deletions

View file

@ -37,6 +37,10 @@
* **csd.preferred** can now be set to `none` to disable window
decorations. Note that some compositors will render SSDs despite
this option being used (https://codeberg.org/dnkl/foot/issues/163).
* Terminal content is now auto-scrolled when moving the mouse above or
below the window while selecting
(https://codeberg.org/dnkl/foot/issues/149).
### Changed
### Deprecated

38
input.c
View file

@ -1325,10 +1325,46 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
= old_col != seat->mouse.col || old_row != seat->mouse.row;
/* Cursor is inside the grid, i.e. *not* in the margins */
bool cursor_is_on_grid = seat->mouse.col >= 0 && seat->mouse.row >= 0;
const bool cursor_is_on_grid = seat->mouse.col >= 0 && seat->mouse.row >= 0;
enum selection_scroll_direction auto_scroll_direction
= y < term->margins.top ? SELECTION_SCROLL_UP
: y > term->height - term->margins.bottom ? SELECTION_SCROLL_DOWN
: SELECTION_SCROLL_NOT;
if (auto_scroll_direction == SELECTION_SCROLL_NOT)
selection_stop_scroll_timer(term);
/* Update selection */
if (!term->is_searching) {
if (auto_scroll_direction != SELECTION_SCROLL_NOT) {
/*
* Start selection auto-scrolling
*
* The speed of the scrolling is proportional to the
* distance between the mouse and the grid; the
* further away the mouse is, the faster we scroll.
*
* Note that the speed is measured in intervals (in
* ns) between each timed scroll of a single line.
*
* Thus, the further away the mouse is, the smaller
* interval value we use.
*/
int distance = auto_scroll_direction == SELECTION_SCROLL_UP
? term->margins.top - y
: y - (term->height - term->margins.bottom);
assert(distance > 0);
int divisor
= distance * term->conf->scrollback.multiplier / term->scale;
selection_start_scroll_timer(
term, 400000000 / (divisor > 0 ? divisor : 1),
auto_scroll_direction, selection_col);
}
if (cursor_is_on_new_cell || term->selection.end.row < 0)
selection_update(term, selection_col, selection_row);
}

View file

@ -15,6 +15,7 @@
#include "log.h"
#include "async.h"
#include "commands.h"
#include "config.h"
#include "extract.h"
#include "grid.h"
@ -619,6 +620,7 @@ selection_finalize(struct seat *seat, struct terminal *term, uint32_t serial)
if (!term->selection.ongoing)
return;
selection_stop_scroll_timer(term);
term->selection.ongoing = false;
if (term->selection.start.row < 0 || term->selection.end.row < 0)
@ -647,6 +649,7 @@ selection_cancel(struct terminal *term)
term->selection.start.row, term->selection.start.col,
term->selection.end.row, term->selection.end.col);
selection_stop_scroll_timer(term);
if (term->selection.start.row >= 0 && term->selection.end.row >= 0) {
foreach_selected(
@ -789,6 +792,108 @@ selection_mark_row(
selection_finalize(seat, term, serial);
}
static bool
fdm_scroll_timer(struct fdm *fdm, int fd, int events, void *data)
{
if (events & EPOLLHUP)
return false;
struct terminal *term = data;
uint64_t expiration_count;
ssize_t ret = read(
term->selection.auto_scroll.fd,
&expiration_count, sizeof(expiration_count));
if (ret < 0) {
if (errno == EAGAIN)
return true;
LOG_ERRNO("failed to read selection scroll timer");
return false;
}
switch (term->selection.auto_scroll.direction) {
case SELECTION_SCROLL_NOT:
return true;
case SELECTION_SCROLL_UP:
cmd_scrollback_up(term, expiration_count);
selection_update(term, term->selection.auto_scroll.col, 0);
break;
case SELECTION_SCROLL_DOWN:
cmd_scrollback_down(term, expiration_count);
selection_update(term, term->selection.auto_scroll.col, term->rows - 1);
break;
}
return true;
}
void
selection_start_scroll_timer(struct terminal *term, int interval_ns,
enum selection_scroll_direction direction, int col)
{
assert(direction != SELECTION_SCROLL_NOT);
if (!term->selection.ongoing)
return;
if (term->selection.auto_scroll.fd < 0) {
int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (fd < 0) {
LOG_ERRNO("failed to create selection scroll timer");
goto err;
}
if (!fdm_add(term->fdm, fd, EPOLLIN, &fdm_scroll_timer, term)) {
close(fd);
return;
}
term->selection.auto_scroll.fd = fd;
}
struct itimerspec timer;
if (timerfd_gettime(term->selection.auto_scroll.fd, &timer) < 0) {
LOG_ERRNO("failed to get current selection scroll timer value");
goto err;
}
if (timer.it_value.tv_sec == 0 && timer.it_value.tv_nsec == 0)
timer.it_value.tv_nsec = 1;
timer.it_interval.tv_sec = interval_ns / 1000000000;
timer.it_interval.tv_nsec = interval_ns % 1000000000;
if (timerfd_settime(term->selection.auto_scroll.fd, 0, &timer, NULL) < 0) {
LOG_ERRNO("failed to set new selection scroll timer value");
goto err;
}
term->selection.auto_scroll.direction = direction;
term->selection.auto_scroll.col = col;
return;
err:
selection_stop_scroll_timer(term);
return;
}
void
selection_stop_scroll_timer(struct terminal *term)
{
if (term->selection.auto_scroll.fd < 0) {
assert(term->selection.auto_scroll.direction == SELECTION_SCROLL_NOT);
return;
}
fdm_del(term->fdm, term->selection.auto_scroll.fd);
term->selection.auto_scroll.fd = -1;
term->selection.auto_scroll.direction = SELECTION_SCROLL_NOT;
}
static void
target(void *data, struct wl_data_source *wl_data_source, const char *mime_type)

View file

@ -74,3 +74,8 @@ void text_from_primary(
struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user),
void (*dont)(void *user), void *user);
void selection_start_scroll_timer(
struct terminal *term, int interval_ns,
enum selection_scroll_direction direction, int col);
void selection_stop_scroll_timer(struct terminal *term);

View file

@ -985,6 +985,9 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
.selection = {
.start = {-1, -1},
.end = {-1, -1},
.auto_scroll = {
.fd = -1,
},
},
.normal = {.scroll_damage = tll_init(), .sixel_images = tll_init()},
.alt = {.scroll_damage = tll_init(), .sixel_images = tll_init()},
@ -1164,6 +1167,7 @@ term_shutdown(struct terminal *term)
term_cursor_blink_disable(term);
fdm_del(term->fdm, term->selection.auto_scroll.fd);
fdm_del(term->fdm, term->render.app_sync_updates.timer_fd);
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);
@ -1176,6 +1180,7 @@ term_shutdown(struct terminal *term)
else
close(term->ptmx);
term->selection.auto_scroll.fd = -1;
term->render.app_sync_updates.timer_fd = -1;
term->delayed_render_timer.lower_fd = -1;
term->delayed_render_timer.upper_fd = -1;
@ -1226,6 +1231,7 @@ term_destroy(struct terminal *term)
}
}
fdm_del(term->fdm, term->selection.auto_scroll.fd);
fdm_del(term->fdm, term->render.app_sync_updates.timer_fd);
fdm_del(term->fdm, term->delayed_render_timer.lower_fd);
fdm_del(term->fdm, term->delayed_render_timer.upper_fd);

View file

@ -182,6 +182,7 @@ enum cursor_style { CURSOR_BLOCK, CURSOR_UNDERLINE, CURSOR_BAR };
enum selection_kind { SELECTION_NONE, SELECTION_NORMAL, SELECTION_BLOCK };
enum selection_direction {SELECTION_UNDIR, SELECTION_LEFT, SELECTION_RIGHT};
enum selection_scroll_direction {SELECTION_SCROLL_NOT, SELECTION_SCROLL_UP, SELECTION_SCROLL_DOWN};
struct ptmx_buffer {
void *data;
@ -349,6 +350,12 @@ struct terminal {
struct coord start;
struct coord end;
bool ongoing;
struct {
int fd;
int col;
enum selection_scroll_direction direction;
} auto_scroll;
} selection;
bool is_searching;