diff --git a/window-copy.c b/window-copy.c index aedbba99b..aec41d34f 100644 --- a/window-copy.c +++ b/window-copy.c @@ -48,6 +48,8 @@ static int window_copy_pagedown1(struct window_mode_entry *, int, int); static void window_copy_next_paragraph(struct window_mode_entry *); static void window_copy_previous_paragraph(struct window_mode_entry *); static void window_copy_redraw_selection(struct window_mode_entry *, u_int); +static void window_copy_redraw_lines1(struct window_mode_entry *, u_int, + u_int, int); static void window_copy_redraw_lines(struct window_mode_entry *, u_int, u_int); static void window_copy_redraw_screen(struct window_mode_entry *); @@ -67,6 +69,8 @@ static u_int window_copy_cursor_unoffset(struct window_mode_entry *, u_int, u_int); static void window_copy_write_line(struct window_mode_entry *, struct screen_write_ctx *, u_int); +static void window_copy_write_line1(struct window_mode_entry *, + struct screen_write_ctx *, u_int, int); static void window_copy_write_lines(struct window_mode_entry *, struct screen_write_ctx *, u_int, u_int); static char *window_copy_match_at_cursor(struct window_copy_mode_data *); @@ -103,6 +107,10 @@ static void window_copy_goto_line(struct window_mode_entry *, const char *); static void window_copy_update_cursor(struct window_mode_entry *, u_int, u_int); static void window_copy_start_selection(struct window_mode_entry *); +static int window_copy_mouse_in_selection(struct window_mode_entry *, + u_int, u_int, int *, int *); +static int window_copy_update_selection_view(struct window_mode_entry *, + int, int); static int window_copy_adjust_selection(struct window_mode_entry *, u_int *, u_int *); static int window_copy_set_selection(struct window_mode_entry *, int, int); @@ -211,6 +219,7 @@ enum { }; enum window_copy_cmd_action { + WINDOW_COPY_CMD_NOREDRAW, WINDOW_COPY_CMD_NOTHING, WINDOW_COPY_CMD_REDRAW, WINDOW_COPY_CMD_CANCEL, @@ -854,7 +863,7 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp, window_copy_cursor_end_of_line(wme); } - if (scroll_exit && data->oy == 0) { + if (scroll_exit && data->oy == 0 && data->screen.sel == NULL) { window_pane_reset_mode(wp); return; } @@ -972,7 +981,7 @@ window_copy_pagedown1(struct window_mode_entry *wme, int half_page, window_copy_cursor_end_of_line(wme); } - if (scroll_exit && data->oy == 0) + if (scroll_exit && data->oy == 0 && data->screen.sel == NULL) return (1); if (data->searchmark != NULL && !data->timeout) window_copy_search_marks(wme, NULL, data->searchregex, 1); @@ -1548,7 +1557,7 @@ window_copy_cmd_copy_selection_no_clear(struct window_copy_cmd_state *cs) window_copy_copy_selection(wme, prefix, set_paste, set_clip); free(prefix); - return (WINDOW_COPY_CMD_NOTHING); + return (WINDOW_COPY_CMD_NOREDRAW); } static enum window_copy_cmd_action @@ -2349,11 +2358,28 @@ window_copy_cmd_scroll_down(struct window_copy_cmd_state *cs) struct window_mode_entry *wme = cs->wme; struct window_copy_mode_data *data = wme->data; u_int np = wme->prefix; + int dragging; - for (; np != 0; np--) + if (data->oy == 0) + return (WINDOW_COPY_CMD_NOREDRAW); + + dragging = (cs->c != NULL && cs->c->tty.mouse_drag_flag != 0); + if (data->screen.sel != NULL && !dragging) { + data->cursordrag = CURSORDRAG_NONE; + data->lineflag = LINE_SEL_NONE; + window_copy_scroll_up(wme, np); + return (WINDOW_COPY_CMD_NOTHING); + } + + for (; np != 0; np--) { + if (data->scroll_exit && data->oy == 0 && + data->screen.sel != NULL) + break; window_copy_cursor_down(wme, 1); - if (data->scroll_exit && data->oy == 0) - return (WINDOW_COPY_CMD_CANCEL); + if (data->scroll_exit && data->oy == 0 && + data->screen.sel == NULL) + return (WINDOW_COPY_CMD_CANCEL); + } return (WINDOW_COPY_CMD_NOTHING); } @@ -2375,7 +2401,20 @@ static enum window_copy_cmd_action window_copy_cmd_scroll_up(struct window_copy_cmd_state *cs) { struct window_mode_entry *wme = cs->wme; + struct window_copy_mode_data *data = wme->data; u_int np = wme->prefix; + int dragging; + + if (data->oy == screen_hsize(data->backing)) + return (WINDOW_COPY_CMD_NOREDRAW); + + dragging = (cs->c != NULL && cs->c->tty.mouse_drag_flag != 0); + if (data->screen.sel != NULL && !dragging) { + data->cursordrag = CURSORDRAG_NONE; + data->lineflag = LINE_SEL_NONE; + window_copy_scroll_down(wme, np); + return (WINDOW_COPY_CMD_NOTHING); + } for (; np != 0; np--) window_copy_cursor_up(wme, 1); @@ -2551,7 +2590,7 @@ window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state *cs) free(command); free(prefix); - return (WINDOW_COPY_CMD_NOTHING); + return (WINDOW_COPY_CMD_NOREDRAW); } static enum window_copy_cmd_action @@ -3764,6 +3803,8 @@ window_copy_command(struct window_mode_entry *wme, struct client *c, window_pane_reset_mode(wp); else if (action == WINDOW_COPY_CMD_REDRAW) window_copy_redraw_screen(wme); + else if (action == WINDOW_COPY_CMD_NOREDRAW) + return; else if (action == WINDOW_COPY_CMD_NOTHING) { /* * Nothing is not actually nothing - most commands at least @@ -5142,6 +5183,13 @@ window_copy_get_current_offset(struct window_pane *wp, u_int *offset, static void window_copy_write_line(struct window_mode_entry *wme, struct screen_write_ctx *ctx, u_int py) +{ + window_copy_write_line1(wme, ctx, py, 1); +} + +static void +window_copy_write_line1(struct window_mode_entry *wme, + struct screen_write_ctx *ctx, u_int py, int clear) { struct window_pane *wp = wme->wp; struct window_copy_mode_data *data = wme->data; @@ -5166,7 +5214,8 @@ window_copy_write_line(struct window_mode_entry *wme, content_sx = sx; screen_write_cursormove(ctx, 0, py, 0); - screen_write_clearline(ctx, 8); + if (clear) + screen_write_clearline(ctx, 8); ft = format_create_defaults(NULL, NULL, NULL, NULL, wp); @@ -5265,11 +5314,18 @@ window_copy_redraw_selection(struct window_mode_entry *wme, u_int old_y) if (end < gd->sy + data->oy - 1) end++; } - window_copy_redraw_lines(wme, start, end - start + 1); + window_copy_redraw_lines1(wme, start, end - start + 1, 0); } static void window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny) +{ + window_copy_redraw_lines1(wme, py, ny, 1); +} + +static void +window_copy_redraw_lines1(struct window_mode_entry *wme, u_int py, u_int ny, + int clear) { struct window_pane *wp = wme->wp; struct window_copy_mode_data *data = wme->data; @@ -5280,7 +5336,7 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny) if (window_copy_line_number_width(wme) != 0) { screen_write_start(&ctx, &data->screen); for (i = py; i < py + ny; i++) - window_copy_write_line(wme, &ctx, i); + window_copy_write_line1(wme, &ctx, i, clear); screen_write_cursormove(&ctx, window_copy_cursor_offset(wme, data->cx, screen_size_x(s)), data->cy, 0); @@ -5294,7 +5350,7 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny) else screen_write_start_pane(&ctx, wp, NULL); for (i = py; i < py + ny; i++) - window_copy_write_line(wme, &ctx, i); + window_copy_write_line1(wme, &ctx, i, clear); screen_write_cursormove(&ctx, window_copy_cursor_offset(wme, data->cx, screen_size_x(s)), data->cy, 0); @@ -5486,6 +5542,71 @@ window_copy_start_selection(struct window_mode_entry *wme) window_copy_set_selection(wme, 1, 0); } +static int +window_copy_mouse_in_selection(struct window_mode_entry *wme, u_int x, u_int y, + int *on_start, int *on_end) +{ + struct window_copy_mode_data *data = wme->data; + u_int hsize, screeny; + u_int mx, my, selx, sely, endselx, endsely; + long long mpos, spos, epos, dstart, dend; + + if (on_start != NULL) + *on_start = 0; + if (on_end != NULL) + *on_end = 0; + if (data->screen.sel == NULL) + return (0); + + hsize = screen_hsize(data->backing); + screeny = hsize - data->oy; + + selx = window_copy_cursor_offset(wme, data->selx, + screen_size_x(&data->screen)); + sely = data->sely - screeny; + if (data->sely >= screeny && sely < screen_size_y(&data->screen) && + x == selx && y == sely) { + if (on_start != NULL) + *on_start = 1; + return (1); + } + + endselx = window_copy_cursor_offset(wme, data->endselx, + screen_size_x(&data->screen)); + endsely = data->endsely - screeny; + if (data->endsely >= screeny && + endsely < screen_size_y(&data->screen) && + x == endselx && y == endsely) { + if (on_end != NULL) + *on_end = 1; + return (1); + } + + if (!screen_check_selection(&data->screen, x, y)) + return (0); + + if (on_start != NULL || on_end != NULL) { + mx = window_copy_cursor_unoffset(wme, x, + screen_size_x(&data->screen)); + my = screeny + y; + mpos = (long long)my * (screen_size_x(&data->screen) + 1) + mx; + spos = (long long)data->sely * + (screen_size_x(&data->screen) + 1) + data->selx; + epos = (long long)data->endsely * + (screen_size_x(&data->screen) + 1) + data->endselx; + dstart = llabs(mpos - spos); + dend = llabs(mpos - epos); + if (dstart <= dend) { + if (on_start != NULL) + *on_start = 1; + } else { + if (on_end != NULL) + *on_end = 1; + } + } + return (1); +} + static int window_copy_adjust_selection(struct window_mode_entry *wme, u_int *selx, u_int *sely) @@ -5531,6 +5652,31 @@ window_copy_update_selection(struct window_mode_entry *wme, int may_redraw, return (window_copy_set_selection(wme, may_redraw, no_reset)); } +static int +window_copy_update_selection_view(struct window_mode_entry *wme, int may_redraw, + int no_reset) +{ + struct window_copy_mode_data *data = wme->data; + u_int selx, sely, endselx, endsely; + int changed; + + if (data->cursordrag != CURSORDRAG_NONE) + return (window_copy_update_selection(wme, may_redraw, no_reset)); + + selx = data->selx; + sely = data->sely; + endselx = data->endselx; + endsely = data->endsely; + + changed = window_copy_update_selection(wme, may_redraw, 1); + + data->selx = selx; + data->sely = sely; + data->endselx = endselx; + data->endsely = endsely; + return (changed); +} + static int window_copy_set_selection(struct window_mode_entry *wme, int may_redraw, int no_reset) @@ -6560,7 +6706,7 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny) if (data->searchmark != NULL && !data->timeout) window_copy_search_marks(wme, NULL, data->searchregex, 1); - window_copy_update_selection(wme, 0, 0); + window_copy_update_selection_view(wme, 0, 0); if (window_copy_line_numbers_active(wme)) { if (window_copy_line_number_mode(wme) != WINDOW_COPY_LINE_NUMBERS_ABSOLUTE) { @@ -6629,7 +6775,7 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny) if (data->searchmark != NULL && !data->timeout) window_copy_search_marks(wme, NULL, data->searchregex, 1); - window_copy_update_selection(wme, 0, 0); + window_copy_update_selection_view(wme, 0, 0); if (window_copy_line_numbers_active(wme)) { if (window_copy_line_number_mode(wme) != WINDOW_COPY_LINE_NUMBERS_ABSOLUTE) { @@ -6718,6 +6864,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m) struct window_mode_entry *wme; struct window_copy_mode_data *data; u_int x, y, yg; + int inside_selection, on_start, on_end; if (c == NULL) return; @@ -6738,10 +6885,16 @@ window_copy_start_drag(struct client *c, struct mouse_event *m) c->tty.mouse_drag_release = window_copy_drag_release; data = wme->data; + on_start = on_end = 0; + inside_selection = window_copy_mouse_in_selection(wme, x, y, + &on_start, &on_end); x = window_copy_cursor_unoffset(wme, x, screen_size_x(&data->screen)); yg = screen_hsize(data->backing) + y - data->oy; - if (x < data->selrx || x > data->endselrx || yg != data->selry) + if (on_start || on_end || !inside_selection || + x < data->selrx || x > data->endselrx || yg != data->selry) { + data->lineflag = LINE_SEL_NONE; data->selflag = SEL_CHAR; + } switch (data->selflag) { case SEL_WORD: if (data->separators != NULL) { @@ -6757,7 +6910,15 @@ window_copy_start_drag(struct client *c, struct mouse_event *m) break; case SEL_CHAR: window_copy_update_cursor(wme, x, y); - window_copy_start_selection(wme); + if (!inside_selection) + window_copy_start_selection(wme); + else { + if (on_start) + data->cursordrag = CURSORDRAG_SEL; + else if (on_end) + data->cursordrag = CURSORDRAG_ENDSEL; + window_copy_update_selection(wme, 1, 0); + } break; } @@ -6833,6 +6994,7 @@ window_copy_drag_release(struct client *c, struct mouse_event *m) data = wme->data; if (window_copy_line_numbers_active(wme)) window_copy_drag_update(c, m); + data->cursordrag = CURSORDRAG_NONE; evtimer_del(&data->dragtimer); }