From d90e7c4086232826bff81b9507cc59076bc1e749 Mon Sep 17 00:00:00 2001 From: ray Date: Wed, 13 Nov 2013 12:32:41 +0000 Subject: [PATCH] o Simplify POS_INDEX macro calculation. o New macro POS_COPY to copy between term_pos_t. o Add vtbuf_wth/vtbuf_htw helpers, to translate between screen coordinates and circular history buffer location. o Update vtbuf_iscursor to mark region selected by mouse. o New helper vtbuf_flush_mark, to update regions where copy/paste mark changed. o New method vtbuf_get_marked_len to get storage size for paste buffer. o vtbuf_extract_marked fill (caller allocated buffer) with selected region data. o Simplify mouse handler for copy/paste, and use vtbuf_flush_mark to update. o New method vtbuf_scroll_mode, to help indicate Scroll mode by hiding cursor. o Update header with new vtbuf methods. o Add new vt_driver method vd_markedwin, to hold last window with selection. o Enable paste support in core module. Sponsored by: The FreeBSD Foundation Pointed by: Claude Buisson (Scroll mode indication) --- sys/dev/vt/vt.h | 12 ++- sys/dev/vt/vt_buf.c | 232 ++++++++++++++++++++++++++++++++++--------- sys/dev/vt/vt_core.c | 50 ++++++++-- 3 files changed, 234 insertions(+), 60 deletions(-) diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h index 9ade99f61897..6f9dba708314 100644 --- a/sys/dev/vt/vt.h +++ b/sys/dev/vt/vt.h @@ -102,6 +102,7 @@ struct vt_device { struct vt_window *vd_windows[VT_MAXWINDOWS]; /* (c) Windows. */ struct vt_window *vd_curwindow; /* (d) Current window. */ struct vt_window *vd_savedwindow;/* (?) Saved for suspend. */ + struct vt_window *vd_markedwin; /* (?) Copy/paste buf owner. */ const struct vt_driver *vd_driver; /* (c) Graphics driver. */ void *vd_softc; /* (u) Driver data. */ uint16_t vd_mx; /* (?) Mouse X. */ @@ -174,19 +175,23 @@ void vtbuf_putchar(struct vt_buf *, const term_pos_t *, term_char_t); void vtbuf_cursor_position(struct vt_buf *, const term_pos_t *); void vtbuf_mouse_cursor_position(struct vt_buf *vb, int col, int row); void vtbuf_cursor_visibility(struct vt_buf *, int); +void vtbuf_scroll_mode(struct vt_buf *vb, int yes); void vtbuf_undirty(struct vt_buf *, term_rect_t *, struct vt_bufmask *); void vtbuf_sethistory_size(struct vt_buf *, int); -void vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row); +int vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row); int vtbuf_iscursor(struct vt_buf *vb, int row, int col); +int vtbuf_get_marked_len(struct vt_buf *vb); +void vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz); +#define VTB_MARK_NONE 0 #define VTB_MARK_END 1 #define VTB_MARK_START 2 #define VTB_MARK_WORD 3 #define VTB_MARK_ROW 4 #define VTB_MARK_EXTEND 5 -#define VTBUF_SLCK_ENABLE(vb) (vb)->vb_flags |= VBF_SCROLL -#define VTBUF_SLCK_DISABLE(vb) (vb)->vb_flags &= ~VBF_SCROLL +#define VTBUF_SLCK_ENABLE(vb) vtbuf_scroll_mode((vb), 1) +#define VTBUF_SLCK_DISABLE(vb) vtbuf_scroll_mode((vb), 0) #define VTBUF_MAX_HEIGHT(vb) \ ((vb)->vb_history_size) @@ -310,6 +315,7 @@ static struct vt_device driver ## _consdev = { \ .vd_flags = VDF_INVALID, \ .vd_windows = { [VT_CONSWINDOW] = &driver ## _conswindow, }, \ .vd_curwindow = &driver ## _conswindow, \ + .vd_markedwin = NULL, \ }; \ static term_char_t driver ## _constextbuf[(width) * \ (VBF_DEFAULT_HISTORY_SIZE)]; \ diff --git a/sys/dev/vt/vt_buf.c b/sys/dev/vt/vt_buf.c index efed9476dfd3..533ee527e840 100644 --- a/sys/dev/vt/vt_buf.c +++ b/sys/dev/vt/vt_buf.c @@ -47,7 +47,12 @@ static MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); #define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) #define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) -#define POS_INDEX(vb, c, r) ((r) * (vb)->vb_scr_size.tp_col + (c)) +#define POS_INDEX(c, r) (((r) << 12) + (c)) +#define POS_COPY(d, s) do { \ + (d).tp_col = (s).tp_col; \ + (d).tp_row = (s).tp_row; \ +} while (0) + /* * line4 @@ -130,16 +135,58 @@ vthistory_getpos(const struct vt_buf *vb, unsigned int *offset) *offset = vb->vb_roffset; } +/* Translate current view row number to history row. */ +static int +vtbuf_wth(struct vt_buf *vb, int row) +{ + + return ((vb->vb_roffset + row) % vb->vb_history_size); +} + +/* Translate history row to current view row number. */ +static int +vtbuf_htw(struct vt_buf *vb, int row) +{ + + /* + * total 1000 rows. + * History offset roffset winrow + * 205 200 ((205 - 200 + 1000) % 1000) = 5 + * 90 990 ((90 - 990 + 1000) % 1000) = 100 + */ + return ((row - vb->vb_roffset + vb->vb_history_size) % + vb->vb_history_size); +} + int vtbuf_iscursor(struct vt_buf *vb, int row, int col) { - if ((vb->vb_flags & VBF_CURSOR) && (vb->vb_cursor.tp_row == row) && - (vb->vb_cursor.tp_col == col)) + int sc, sr, ec, er, tmp; + + if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && + (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) return (1); - if ((POS_INDEX(vb, vb->vb_mark_start.tp_col, vb->vb_mark_start.tp_row) < - POS_INDEX(vb, col, row)) && (POS_INDEX(vb, col, row) <= - POS_INDEX(vb, vb->vb_mark_start.tp_col, vb->vb_mark_start.tp_row))) + /* Mark cut/paste region. */ + + /* + * Luckily screen view is not like circular buffer, so we will + * calculate in screen coordinates. Translate first. + */ + sc = vb->vb_mark_start.tp_col; + sr = vtbuf_htw(vb, vb->vb_mark_start.tp_row); + ec = vb->vb_mark_end.tp_col; + er = vtbuf_htw(vb, vb->vb_mark_end.tp_row); + + + /* Swap start and end if start > end. */ + if (POS_INDEX(sc, sr) > POS_INDEX(ec, er)) { + tmp = sc; sc = ec; ec = tmp; + tmp = sr; sr = er; er = tmp; + } + + if ((POS_INDEX(sc, sr) <= POS_INDEX(col, row)) && + (POS_INDEX(col, row) < POS_INDEX(ec, er))) return (1); return (0); @@ -347,6 +394,10 @@ vtbuf_init_early(struct vt_buf *vb) vb->vb_flags |= VBF_CURSOR; vb->vb_roffset = 0; vb->vb_curroffset = 0; + vb->vb_mark_start.tp_row = 0; + vb->vb_mark_start.tp_col = 0; + vb->vb_mark_end.tp_row = 0; + vb->vb_mark_end.tp_col = 0; vtbuf_init_rows(vb); vtbuf_make_undirty(vb); @@ -492,63 +543,127 @@ vtbuf_mouse_cursor_position(struct vt_buf *vb, int col, int row) vtbuf_dirty(vb, &area); } -void -vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) +static void +vtbuf_flush_mark(struct vt_buf *vb) { term_rect_t area; - vt_axis_t tmp; - - switch (type) { - case VTB_MARK_END: - case VTB_MARK_EXTEND: - vb->vb_mark_end.tp_col = col; - vb->vb_mark_end.tp_row = row; - break; - case VTB_MARK_START: - vb->vb_mark_start.tp_col = col; - vb->vb_mark_start.tp_row = row; - /* Start again, so clear end point. */ - vb->vb_mark_end.tp_col = 0; - vb->vb_mark_end.tp_row = 0; - break; - case VTB_MARK_WORD: - vb->vb_mark_start.tp_col = 0; /* XXX */ - vb->vb_mark_end.tp_col = 10; /* XXX */ - vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = row; - break; - case VTB_MARK_ROW: - vb->vb_mark_start.tp_col = 0; - vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; - vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = row; - break; - } - - /* Swap start and end if start > end. */ - if (POS_INDEX(vb, vb->vb_mark_start.tp_col, vb->vb_mark_start.tp_row) > - POS_INDEX(vb, vb->vb_mark_end.tp_col, vb->vb_mark_end.tp_row)) { - tmp = vb->vb_mark_start.tp_col; - vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; - vb->vb_mark_end.tp_col = tmp; - tmp = vb->vb_mark_start.tp_row; - vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row; - vb->vb_mark_end.tp_row = tmp; - } + int s, e; /* Notify renderer to update marked region. */ if (vb->vb_mark_start.tp_col || vb->vb_mark_end.tp_col || vb->vb_mark_start.tp_row || vb->vb_mark_end.tp_row) { + s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); + e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); + area.tr_begin.tp_col = 0; - area.tr_begin.tp_row = MIN(vb->vb_mark_start.tp_row, - vb->vb_mark_end.tp_row); + area.tr_begin.tp_row = MIN(s, e); area.tr_end.tp_col = vb->vb_scr_size.tp_col; - area.tr_end.tp_row = MAX(vb->vb_mark_start.tp_row, - vb->vb_mark_end.tp_row); + area.tr_end.tp_row = MAX(s, e) + 1; vtbuf_dirty(vb, &area); } +} +int +vtbuf_get_marked_len(struct vt_buf *vb) +{ + int ei, si, sz; + term_pos_t s, e; + + /* Swap according to window coordinates. */ + if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), vb->vb_mark_start.tp_col) > + POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), vb->vb_mark_end.tp_col)) { + POS_COPY(e, vb->vb_mark_start); + POS_COPY(s, vb->vb_mark_end); + } else { + POS_COPY(s, vb->vb_mark_start); + POS_COPY(e, vb->vb_mark_end); + } + + si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; + ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; + + /* Number symbols and number of rows to inject \n */ + sz = ei - si + ((e.tp_row - s.tp_row) * 2) + 1; + + return (sz * sizeof(term_char_t)); +} + +void +vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) +{ + int i, r, c, cs, ce; + term_pos_t s, e; + + /* Swap according to window coordinates. */ + if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), vb->vb_mark_start.tp_col) > + POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), vb->vb_mark_end.tp_col)) { + POS_COPY(e, vb->vb_mark_start); + POS_COPY(s, vb->vb_mark_end); + } else { + POS_COPY(s, vb->vb_mark_start); + POS_COPY(e, vb->vb_mark_end); + } + + i = 0; + for (r = s.tp_row; r <= e.tp_row; r ++) { + cs = (r == s.tp_row)?s.tp_col:0; + ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; + for (c = cs; c < ce; c ++) { + buf[i++] = vb->vb_rows[r][c]; + } + buf[i++] = '\r'; + buf[i++] = '\n'; + } +} + +int +vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) +{ + + switch (type) { + case VTB_MARK_END: + case VTB_MARK_EXTEND: + vtbuf_flush_mark(vb); /* Clean old mark. */ + vb->vb_mark_end.tp_col = col; + vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); + break; + case VTB_MARK_START: + vtbuf_flush_mark(vb); /* Clean old mark. */ + vb->vb_mark_start.tp_col = col; + vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); + /* Start again, so clear end point. */ + vb->vb_mark_end.tp_col = col; + vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); + break; + case VTB_MARK_WORD: + vtbuf_flush_mark(vb); /* Clean old mark. */ + vb->vb_mark_start.tp_col = 0; /* XXX */ + vb->vb_mark_end.tp_col = 10; /* XXX */ + vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = + vtbuf_wth(vb, row); + break; + case VTB_MARK_ROW: + vtbuf_flush_mark(vb); /* Clean old mark. */ + vb->vb_mark_start.tp_col = 0; + vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; + vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = + vtbuf_wth(vb, row); + break; + case VTB_MARK_NONE: + break; + default: + /* panic? */ + return (0); + } + if (type != VTB_MARK_NONE) { + /* Draw new marked region. */ + vtbuf_flush_mark(vb); + return (1); + } + return (0); } void @@ -568,3 +683,22 @@ vtbuf_cursor_visibility(struct vt_buf *vb, int yes) if (oflags != nflags) vtbuf_dirty_cell(vb, &vb->vb_cursor); } + +void +vtbuf_scroll_mode(struct vt_buf *vb, int yes) +{ + int oflags, nflags; + + VTBUF_LOCK(vb); + oflags = vb->vb_flags; + if (yes) + vb->vb_flags |= VBF_SCROLL; + else + vb->vb_flags &= ~VBF_SCROLL; + nflags = vb->vb_flags; + VTBUF_UNLOCK(vb); + + if (oflags != nflags) + vtbuf_dirty_cell(vb, &vb->vb_cursor); +} + diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index 44777a6db207..2eed24f03ab5 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -1069,7 +1069,8 @@ vt_mouse_event(int type, int x, int y, int event, int cnt) struct vt_window *vw; struct vt_font *vf; term_pos_t size; - int mark; + term_char_t *buf; + int i, len, mark; vd = main_vd; vw = vd->vd_curwindow; @@ -1100,10 +1101,17 @@ vt_mouse_event(int type, int x, int y, int event, int cnt) vd->vd_mx = x; vd->vd_my = y; - if (vd->vd_mstate & MOUSE_BUTTON1DOWN) - vtbuf_set_mark(&vw->vw_buf, VTB_MARK_END, - vd->vd_mx / vf->vf_width, - vd->vd_my / vf->vf_height); + if ((vd->vd_mstate & MOUSE_BUTTON1DOWN) && + (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_END, + vd->vd_mx / vf->vf_width, + vd->vd_my / vf->vf_height) == 1)) { + + /* + * We have something marked to copy, so update pointer + * to window with selection. + */ + vd->vd_markedwin = vw; + } return; /* Done */ case MOUSE_BUTTON_EVENT: /* Buttons */ @@ -1134,7 +1142,27 @@ vt_mouse_event(int type, int x, int y, int event, int cnt) case 0: /* up */ break; default: - //sc_mouse_paste(cur_scp); + if (vd->vd_markedwin == NULL) + return; + /* Get current selecton size in bytes. */ + len = vtbuf_get_marked_len(&vd->vd_markedwin->vw_buf); + if (len <= 0) + return; + + buf = malloc(len, M_VT, M_WAITOK | M_ZERO); + /* Request cupy/paste buffer data, no more than `len' */ + vtbuf_extract_marked(&vd->vd_markedwin->vw_buf, buf, + len); + + len /= sizeof(term_char_t); + for (i = 0; i < len; i++ ) { + if (buf[i] == '\0') + continue; + terminal_input_char(vw->vw_terminal, buf[i]); + } + + /* Done, so cleanup. */ + free(buf, M_VT); break; } return; /* Done */ @@ -1161,8 +1189,14 @@ vt_mouse_event(int type, int x, int y, int event, int cnt) else vd->vd_mstate &= ~event; - vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, - vd->vd_my / vf->vf_height); + if (vtbuf_set_mark(&vw->vw_buf, mark, vd->vd_mx / vf->vf_width, + vd->vd_my / vf->vf_height) == 1) { + /* + * We have something marked to copy, so update pointer to + * window with selection. + */ + vd->vd_markedwin = vw; + } } static int