Merge branch 'right-mouse-extend-selection'

This commit is contained in:
Daniel Eklöf 2020-04-04 12:10:43 +02:00
commit f0fbfe8e89
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
6 changed files with 189 additions and 19 deletions

View file

@ -21,6 +21,7 @@
the Wayland window.
* **title** option to `footrc`, that sets the initial window title.
* `--title` command line option, that sets the initial window title.
* Right mouse button extends the current selection.
### Changed

View file

@ -163,6 +163,9 @@ These are the default shortcuts. See `man 5 foot` and the example
<kbd>middle</kbd>
: Paste from _primary_ selection
<kbd>right</kbd>
: Extend current selection
<kbd>wheel</kbd>
: Scroll up/down in history

View file

@ -194,6 +194,9 @@ Note that these are just the defaults; they can be changed in the
*middle*
Paste from the _primary_ selection
*right*
Extend current selection
*wheel*
Scroll up/down in history

13
input.c
View file

@ -1174,7 +1174,9 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
switch (state) {
case WL_POINTER_BUTTON_STATE_PRESSED: {
if (button == BTN_LEFT) {
if (button == BTN_LEFT && wayl->mouse.count <= 3) {
selection_cancel(term);
switch (wayl->mouse.count) {
case 1:
selection_start(
@ -1193,6 +1195,10 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
}
}
else if (button == BTN_RIGHT && wayl->mouse.count == 1) {
selection_extend(term, wayl->mouse.col, wayl->mouse.row, serial);
}
else {
for (size_t i = 0; i < ALEN(wayl->conf->bindings.mouse); i++) {
const struct mouse_binding *binding =
@ -1211,7 +1217,6 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
execute_binding(term, binding->action, serial);
break;
}
selection_cancel(term);
}
term_mouse_down(term, button, wayl->mouse.row, wayl->mouse.col);
@ -1219,9 +1224,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
}
case WL_POINTER_BUTTON_STATE_RELEASED:
if (button != BTN_LEFT || term->selection.end.col == -1)
selection_cancel(term);
else
if (button == BTN_LEFT && term->selection.end.col != -1)
selection_finalize(term, serial);
term_mouse_up(term, button, wayl->mouse.row, wayl->mouse.col);

View file

@ -335,6 +335,32 @@ mark_selected(struct terminal *term, struct row *row, struct cell *cell,
cell->attrs.clean = 0;
}
static void
selection_modify(struct terminal *term, struct coord start, struct coord end)
{
assert(selection_enabled(term));
assert(term->selection.start.row != -1);
assert(start.row != -1 && start.col != -1);
assert(end.row != -1 && end.col != -1);
/* Premark all cells that *will* be selected */
foreach_selected(term, start, end, &premark_selected, NULL);
if (term->selection.end.row != -1) {
/* Unmark previous selection, ignoring cells that are part of
* the new selection */
foreach_selected(term, term->selection.start, term->selection.end,
&unmark_selected, NULL);
}
term->selection.start = start;
term->selection.end = end;
/* Mark new selection */
foreach_selected(term, start, end, &mark_selected, NULL);
render_refresh(term);
}
void
selection_update(struct terminal *term, int col, int row)
{
@ -350,26 +376,159 @@ selection_update(struct terminal *term, int col, int row)
assert(term->grid->view + row != -1);
struct coord new_end = {col, term->grid->view + row};
selection_modify(term, term->selection.start, new_end);
}
/* Premark all cells that *will* be selected */
foreach_selected(
term, term->selection.start, new_end, &premark_selected, NULL);
static void
selection_extend_normal(struct terminal *term, int col, int row, uint32_t serial)
{
const struct coord *start = &term->selection.start;
const struct coord *end = &term->selection.end;
if (term->selection.end.row != -1) {
/* Unmark previous selection, ignoring cells that are part of
* the new selection */
foreach_selected(term, term->selection.start, term->selection.end,
&unmark_selected, NULL);
if (start->row > end->row ||
(start->row == end->row && start->col > end->col))
{
const struct coord *tmp = start;
start = end;
end = tmp;
}
term->selection.end = new_end;
assert(term->selection.start.row != -1 && term->selection.end.row != -1);
assert(start->row < end->row || start->col < end->col);
/* Mark new selection */
foreach_selected(
term, term->selection.start, term->selection.end, &mark_selected, NULL);
struct coord new_start, new_end;
render_refresh(term);
if (row < start->row || (row == start->row && col < start->col)) {
/* Extend selection to start *before* current start */
new_start = (struct coord){col, row};
new_end = *end;
}
else if (row > end->row || (row == end->row && col > end->col)) {
/* Extend selection to end *after* current end */
new_start = *start;
new_end = (struct coord){col, row};
}
else {
/* Shrink selection from start or end, depending on which one is closest */
const int linear = row * term->cols + col;
if (abs(linear - (start->row * term->cols + start->col)) <
abs(linear - (end->row * term->cols + end->col)))
{
/* Move start point */
new_start = (struct coord){col, row};
new_end = *end;
}
else {
/* Move end point */
new_start = *start;
new_end = (struct coord){col, row};
}
}
selection_modify(term, new_start, new_end);
}
static void
selection_extend_block(struct terminal *term, int col, int row, uint32_t serial)
{
const struct coord *start = &term->selection.start;
const struct coord *end = &term->selection.end;
struct coord top_left = {
.row = min(start->row, end->row),
.col = min(start->col, end->col),
};
struct coord top_right = {
.row = min(start->row, end->row),
.col = max(start->col, end->col),
};
struct coord bottom_left = {
.row = max(start->row, end->row),
.col = min(start->col, end->col),
};
struct coord bottom_right = {
.row = max(start->row, end->row),
.col = max(start->col, end->col),
};
struct coord new_start;
struct coord new_end;
if (row <= top_left.row ||
abs(row - top_left.row) < abs(row - bottom_left.row))
{
/* Move one of the top corners */
if (abs(col - top_left.col) < abs(col - top_right.col)) {
new_start = (struct coord){col, row};
new_end = bottom_right;
}
else {
new_start = (struct coord){col, row};
new_end = bottom_left;
}
}
else {
/* Move one of the bottom corners */
if (abs(col - bottom_left.col) < abs(col - bottom_right.col)) {
new_start = top_right;
new_end = (struct coord){col, row};
}
else {
new_start = top_left;
new_end = (struct coord){col, row};
}
}
selection_modify(term, new_start, new_end);
}
void
selection_extend(struct terminal *term, int col, int row, uint32_t serial)
{
if (!selection_enabled(term))
return;
if (term->selection.start.row == -1 || term->selection.end.row == -1) {
/* No existing selection */
return;
}
row += term->grid->view;
if ((row == term->selection.start.row && col == term->selection.start.col) ||
(row == term->selection.end.row && col == term->selection.end.col))
{
/* Extension point *is* one of the current end points */
return;
}
switch (term->selection.kind) {
case SELECTION_NONE:
assert(false);
return;
case SELECTION_NORMAL:
selection_extend_normal(term, col, row, serial);
break;
case SELECTION_BLOCK:
selection_extend_block(term, col, row, serial);
break;
}
selection_to_primary(term, serial);
}
static const struct zwp_primary_selection_source_v1_listener primary_selection_source_listener;

View file

@ -14,6 +14,7 @@ void selection_start(
void selection_update(struct terminal *term, int col, int row);
void selection_finalize(struct terminal *term, uint32_t serial);
void selection_cancel(struct terminal *term);
void selection_extend(struct terminal *term, int col, int row, uint32_t serial);
bool selection_on_row_in_view(const struct terminal *term, int row_no);