127cf7d04SAleksandr Rybalko /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 427cf7d04SAleksandr Rybalko * Copyright (c) 2009, 2013 The FreeBSD Foundation 527cf7d04SAleksandr Rybalko * 627cf7d04SAleksandr Rybalko * This software was developed by Ed Schouten under sponsorship from the 727cf7d04SAleksandr Rybalko * FreeBSD Foundation. 827cf7d04SAleksandr Rybalko * 927cf7d04SAleksandr Rybalko * Portions of this software were developed by Oleksandr Rybalko 1027cf7d04SAleksandr Rybalko * under sponsorship from the FreeBSD Foundation. 1127cf7d04SAleksandr Rybalko * 1227cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 1327cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 1427cf7d04SAleksandr Rybalko * are met: 1527cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1627cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1727cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1827cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 1927cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 2027cf7d04SAleksandr Rybalko * 2127cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2227cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2327cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2427cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2527cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2627cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2727cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2827cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2927cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3027cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3127cf7d04SAleksandr Rybalko * SUCH DAMAGE. 3227cf7d04SAleksandr Rybalko */ 3327cf7d04SAleksandr Rybalko 3427cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 3527cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 3627cf7d04SAleksandr Rybalko 3727cf7d04SAleksandr Rybalko #include <sys/param.h> 38*327da507SEd Maste #include <sys/systm.h> 3927cf7d04SAleksandr Rybalko #include <sys/kernel.h> 4027cf7d04SAleksandr Rybalko #include <sys/lock.h> 4127cf7d04SAleksandr Rybalko #include <sys/malloc.h> 4227cf7d04SAleksandr Rybalko #include <sys/mutex.h> 437344ee18SMarius Strobl #include <sys/reboot.h> 4427cf7d04SAleksandr Rybalko 4527cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 4627cf7d04SAleksandr Rybalko 4727cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); 4827cf7d04SAleksandr Rybalko 4927cf7d04SAleksandr Rybalko #define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) 5027cf7d04SAleksandr Rybalko #define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) 5127cf7d04SAleksandr Rybalko 5227cf7d04SAleksandr Rybalko #define POS_INDEX(c, r) (((r) << 12) + (c)) 5327cf7d04SAleksandr Rybalko #define POS_COPY(d, s) do { \ 5427cf7d04SAleksandr Rybalko (d).tp_col = (s).tp_col; \ 5527cf7d04SAleksandr Rybalko (d).tp_row = (s).tp_row; \ 5627cf7d04SAleksandr Rybalko } while (0) 5727cf7d04SAleksandr Rybalko 58c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 5907a45594SRavi Pokala static int vtbuf_htw(const struct vt_buf *vb, int row); 60c0e295deSAleksandr Rybalko static int vtbuf_wth(const struct vt_buf *vb, int row); 61c0e295deSAleksandr Rybalko static int vtbuf_in_this_range(int begin, int test, int end, int sz); 62c0e295deSAleksandr Rybalko #endif 6327cf7d04SAleksandr Rybalko 6427cf7d04SAleksandr Rybalko /* 6527cf7d04SAleksandr Rybalko * line4 6627cf7d04SAleksandr Rybalko * line5 <--- curroffset (terminal output to that line) 6727cf7d04SAleksandr Rybalko * line0 6827cf7d04SAleksandr Rybalko * line1 <--- roffset (history display from that point) 6927cf7d04SAleksandr Rybalko * line2 7027cf7d04SAleksandr Rybalko * line3 7127cf7d04SAleksandr Rybalko */ 7227cf7d04SAleksandr Rybalko int 7327cf7d04SAleksandr Rybalko vthistory_seek(struct vt_buf *vb, int offset, int whence) 7427cf7d04SAleksandr Rybalko { 7527cf7d04SAleksandr Rybalko int diff, top, bottom, roffset; 7627cf7d04SAleksandr Rybalko 7727cf7d04SAleksandr Rybalko /* No scrolling if not enabled. */ 7827cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_SCROLL) == 0) { 7927cf7d04SAleksandr Rybalko if (vb->vb_roffset != vb->vb_curroffset) { 8027cf7d04SAleksandr Rybalko vb->vb_roffset = vb->vb_curroffset; 8127cf7d04SAleksandr Rybalko return (0xffff); 8227cf7d04SAleksandr Rybalko } 8327cf7d04SAleksandr Rybalko return (0); /* No changes */ 8427cf7d04SAleksandr Rybalko } 8527cf7d04SAleksandr Rybalko 861454439cSJean-Sébastien Pédron /* "top" may be a negative integer. */ 871454439cSJean-Sébastien Pédron bottom = vb->vb_curroffset; 881454439cSJean-Sébastien Pédron top = (vb->vb_flags & VBF_HISTORY_FULL) ? 891454439cSJean-Sébastien Pédron bottom + vb->vb_scr_size.tp_row - vb->vb_history_size : 901454439cSJean-Sébastien Pédron 0; 911454439cSJean-Sébastien Pédron 92a10068fdSBjoern A. Zeeb roffset = 0; /* Make gcc happy. */ 9327cf7d04SAleksandr Rybalko switch (whence) { 9427cf7d04SAleksandr Rybalko case VHS_SET: 951454439cSJean-Sébastien Pédron if (offset < 0) 961454439cSJean-Sébastien Pédron offset = 0; 971454439cSJean-Sébastien Pédron roffset = top + offset; 9827cf7d04SAleksandr Rybalko break; 9927cf7d04SAleksandr Rybalko case VHS_CUR: 1001454439cSJean-Sébastien Pédron /* 1011454439cSJean-Sébastien Pédron * Operate on copy of offset value, since it temporary 1021454439cSJean-Sébastien Pédron * can be bigger than amount of rows in buffer. 1031454439cSJean-Sébastien Pédron */ 1041454439cSJean-Sébastien Pédron roffset = vb->vb_roffset; 1051454439cSJean-Sébastien Pédron if (roffset >= bottom + vb->vb_scr_size.tp_row) 1061454439cSJean-Sébastien Pédron roffset -= vb->vb_history_size; 1071454439cSJean-Sébastien Pédron 10827cf7d04SAleksandr Rybalko roffset += offset; 1091454439cSJean-Sébastien Pédron roffset = MAX(roffset, top); 1101454439cSJean-Sébastien Pédron roffset = MIN(roffset, bottom); 1111454439cSJean-Sébastien Pédron 1121454439cSJean-Sébastien Pédron if (roffset < 0) 1131454439cSJean-Sébastien Pédron roffset = vb->vb_history_size + roffset; 1141454439cSJean-Sébastien Pédron 11527cf7d04SAleksandr Rybalko break; 11627cf7d04SAleksandr Rybalko case VHS_END: 11727cf7d04SAleksandr Rybalko /* Go to current offset. */ 1181454439cSJean-Sébastien Pédron roffset = vb->vb_curroffset; 11927cf7d04SAleksandr Rybalko break; 12027cf7d04SAleksandr Rybalko } 12127cf7d04SAleksandr Rybalko 1221454439cSJean-Sébastien Pédron diff = vb->vb_roffset != roffset; 12327cf7d04SAleksandr Rybalko vb->vb_roffset = roffset; 1241454439cSJean-Sébastien Pédron 12527cf7d04SAleksandr Rybalko return (diff); 12627cf7d04SAleksandr Rybalko } 12727cf7d04SAleksandr Rybalko 12827cf7d04SAleksandr Rybalko void 12927cf7d04SAleksandr Rybalko vthistory_addlines(struct vt_buf *vb, int offset) 13027cf7d04SAleksandr Rybalko { 131c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 132c0e295deSAleksandr Rybalko int cur, sz; 133c0e295deSAleksandr Rybalko #endif 13427cf7d04SAleksandr Rybalko 13527cf7d04SAleksandr Rybalko vb->vb_curroffset += offset; 136e1734edfSEd Maste if (vb->vb_curroffset + vb->vb_scr_size.tp_row >= vb->vb_history_size) { 1371454439cSJean-Sébastien Pédron vb->vb_flags |= VBF_HISTORY_FULL; 13827cf7d04SAleksandr Rybalko vb->vb_curroffset %= vb->vb_history_size; 139e1734edfSEd Maste } 14027cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_SCROLL) == 0) { 14127cf7d04SAleksandr Rybalko vb->vb_roffset = vb->vb_curroffset; 14227cf7d04SAleksandr Rybalko } 143c0e295deSAleksandr Rybalko 144c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 145c0e295deSAleksandr Rybalko sz = vb->vb_history_size; 146c0e295deSAleksandr Rybalko cur = vb->vb_roffset + vb->vb_scr_size.tp_row + sz - 1; 147c0e295deSAleksandr Rybalko if (vtbuf_in_this_range(cur, vb->vb_mark_start.tp_row, cur + offset, sz) || 148c0e295deSAleksandr Rybalko vtbuf_in_this_range(cur, vb->vb_mark_end.tp_row, cur + offset, sz)) { 149c0e295deSAleksandr Rybalko /* clear screen selection */ 150c0e295deSAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row; 151c0e295deSAleksandr Rybalko vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 152c0e295deSAleksandr Rybalko } 153c0e295deSAleksandr Rybalko #endif 15427cf7d04SAleksandr Rybalko } 15527cf7d04SAleksandr Rybalko 15627cf7d04SAleksandr Rybalko void 15727cf7d04SAleksandr Rybalko vthistory_getpos(const struct vt_buf *vb, unsigned int *offset) 15827cf7d04SAleksandr Rybalko { 15927cf7d04SAleksandr Rybalko 16027cf7d04SAleksandr Rybalko *offset = vb->vb_roffset; 16127cf7d04SAleksandr Rybalko } 16227cf7d04SAleksandr Rybalko 1630f49db6eSAleksandr Rybalko #ifndef SC_NO_CUTPASTE /* Only mouse support use it now. */ 16407a45594SRavi Pokala /* Translate history row to current view row number. */ 16507a45594SRavi Pokala static int 16607a45594SRavi Pokala vtbuf_htw(const struct vt_buf *vb, int row) 16707a45594SRavi Pokala { 16807a45594SRavi Pokala 16907a45594SRavi Pokala /* 17007a45594SRavi Pokala * total 1000 rows. 17107a45594SRavi Pokala * History offset roffset winrow 17207a45594SRavi Pokala * 205 200 ((205 - 200 + 1000) % 1000) = 5 17307a45594SRavi Pokala * 90 990 ((90 - 990 + 1000) % 1000) = 100 17407a45594SRavi Pokala */ 17507a45594SRavi Pokala return ((row - vb->vb_roffset + vb->vb_history_size) % 17607a45594SRavi Pokala vb->vb_history_size); 17707a45594SRavi Pokala } 17807a45594SRavi Pokala 17927cf7d04SAleksandr Rybalko /* Translate current view row number to history row. */ 18027cf7d04SAleksandr Rybalko static int 181c0e295deSAleksandr Rybalko vtbuf_wth(const struct vt_buf *vb, int row) 18227cf7d04SAleksandr Rybalko { 18327cf7d04SAleksandr Rybalko 18427cf7d04SAleksandr Rybalko return ((vb->vb_roffset + row) % vb->vb_history_size); 18527cf7d04SAleksandr Rybalko } 186c0e295deSAleksandr Rybalko 187c0e295deSAleksandr Rybalko /* 188c0e295deSAleksandr Rybalko * Test if an index in a circular buffer is within a range. 189c0e295deSAleksandr Rybalko * 190c0e295deSAleksandr Rybalko * begin - start index 191c0e295deSAleksandr Rybalko * end - end index 192c0e295deSAleksandr Rybalko * test - test index 193c0e295deSAleksandr Rybalko * sz - size of circular buffer when it turns over 194c0e295deSAleksandr Rybalko */ 195c0e295deSAleksandr Rybalko static int 196c0e295deSAleksandr Rybalko vtbuf_in_this_range(int begin, int test, int end, int sz) 197c0e295deSAleksandr Rybalko { 198c0e295deSAleksandr Rybalko 199c0e295deSAleksandr Rybalko begin %= sz; 200c0e295deSAleksandr Rybalko end %= sz; 201c0e295deSAleksandr Rybalko 202c0e295deSAleksandr Rybalko /* check for inversion */ 203c0e295deSAleksandr Rybalko if (begin > end) 204c0e295deSAleksandr Rybalko return (test >= begin || test < end); 205c0e295deSAleksandr Rybalko else 206c0e295deSAleksandr Rybalko return (test >= begin && test < end); 207c0e295deSAleksandr Rybalko } 2080f49db6eSAleksandr Rybalko #endif 20927cf7d04SAleksandr Rybalko 21027cf7d04SAleksandr Rybalko int 211c6e1a987SJean-Sébastien Pédron vtbuf_iscursor(const struct vt_buf *vb, int row, int col) 21227cf7d04SAleksandr Rybalko { 213c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 214c0e295deSAleksandr Rybalko int sc, sr, sz, ec, er, tmp; 215c0e295deSAleksandr Rybalko #endif 21627cf7d04SAleksandr Rybalko 21727cf7d04SAleksandr Rybalko if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 21827cf7d04SAleksandr Rybalko (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 21927cf7d04SAleksandr Rybalko return (1); 22027cf7d04SAleksandr Rybalko 221c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 22227cf7d04SAleksandr Rybalko /* Mark cut/paste region. */ 223c0e295deSAleksandr Rybalko if (vb->vb_mark_start.tp_col == vb->vb_mark_end.tp_col && 224c0e295deSAleksandr Rybalko vb->vb_mark_start.tp_row == vb->vb_mark_end.tp_row) 225c0e295deSAleksandr Rybalko return (0); 226c0e295deSAleksandr Rybalko 227c0e295deSAleksandr Rybalko sc = vb->vb_mark_start.tp_col; 228c0e295deSAleksandr Rybalko sr = vb->vb_mark_start.tp_row; 229c0e295deSAleksandr Rybalko ec = vb->vb_mark_end.tp_col; 230c0e295deSAleksandr Rybalko er = vb->vb_mark_end.tp_row; 23127cf7d04SAleksandr Rybalko 23227cf7d04SAleksandr Rybalko /* 233c0e295deSAleksandr Rybalko * Information about if the selection was made bottom-top or 234c0e295deSAleksandr Rybalko * top-bottom is lost due to modulo arithmetics and needs to 235c0e295deSAleksandr Rybalko * be recovered: 23627cf7d04SAleksandr Rybalko */ 237c0e295deSAleksandr Rybalko sz = vb->vb_history_size; 238c0e295deSAleksandr Rybalko tmp = (sz + er - sr) % sz; 239c0e295deSAleksandr Rybalko row = vtbuf_wth(vb, row); 24027cf7d04SAleksandr Rybalko 241c0e295deSAleksandr Rybalko /* Swap start and end if start > end */ 242c0e295deSAleksandr Rybalko if ((2 * tmp) > sz || (tmp == 0 && sc > ec)) { 24327cf7d04SAleksandr Rybalko tmp = sc; sc = ec; ec = tmp; 24427cf7d04SAleksandr Rybalko tmp = sr; sr = er; er = tmp; 24527cf7d04SAleksandr Rybalko } 24627cf7d04SAleksandr Rybalko 247c0e295deSAleksandr Rybalko if (vtbuf_in_this_range(POS_INDEX(sc, sr), POS_INDEX(col, row), 248c0e295deSAleksandr Rybalko POS_INDEX(ec, er), POS_INDEX(0, sz))) 24927cf7d04SAleksandr Rybalko return (1); 250c0e295deSAleksandr Rybalko #endif 25127cf7d04SAleksandr Rybalko 25227cf7d04SAleksandr Rybalko return (0); 25327cf7d04SAleksandr Rybalko } 25427cf7d04SAleksandr Rybalko 255547e74a8SJean-Sébastien Pédron void 256547e74a8SJean-Sébastien Pédron vtbuf_lock(struct vt_buf *vb) 257547e74a8SJean-Sébastien Pédron { 258547e74a8SJean-Sébastien Pédron 259547e74a8SJean-Sébastien Pédron VTBUF_LOCK(vb); 260547e74a8SJean-Sébastien Pédron } 261547e74a8SJean-Sébastien Pédron 262547e74a8SJean-Sébastien Pédron void 263547e74a8SJean-Sébastien Pédron vtbuf_unlock(struct vt_buf *vb) 264547e74a8SJean-Sébastien Pédron { 265547e74a8SJean-Sébastien Pédron 266547e74a8SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 267547e74a8SJean-Sébastien Pédron } 268547e74a8SJean-Sébastien Pédron 269547e74a8SJean-Sébastien Pédron void 270547e74a8SJean-Sébastien Pédron vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 27127cf7d04SAleksandr Rybalko { 27227cf7d04SAleksandr Rybalko 27327cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 27427cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 27527cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 27627cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 27727cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 27827cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 27927cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 28027cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 28100c33067SJean-Sébastien Pédron } 28200c33067SJean-Sébastien Pédron 28327cf7d04SAleksandr Rybalko static inline void 284547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(struct vt_buf *vb, const term_pos_t *p) 28527cf7d04SAleksandr Rybalko { 28627cf7d04SAleksandr Rybalko term_rect_t area; 28727cf7d04SAleksandr Rybalko 28827cf7d04SAleksandr Rybalko area.tr_begin = *p; 28927cf7d04SAleksandr Rybalko area.tr_end.tp_row = p->tp_row + 1; 29027cf7d04SAleksandr Rybalko area.tr_end.tp_col = p->tp_col + 1; 291547e74a8SJean-Sébastien Pédron vtbuf_dirty(vb, &area); 29227cf7d04SAleksandr Rybalko } 29327cf7d04SAleksandr Rybalko 29427cf7d04SAleksandr Rybalko static void 29527cf7d04SAleksandr Rybalko vtbuf_make_undirty(struct vt_buf *vb) 29627cf7d04SAleksandr Rybalko { 29727cf7d04SAleksandr Rybalko 29827cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 29927cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 30027cf7d04SAleksandr Rybalko } 30127cf7d04SAleksandr Rybalko 30227cf7d04SAleksandr Rybalko void 303c3a05e54SJean-Sébastien Pédron vtbuf_undirty(struct vt_buf *vb, term_rect_t *r) 30427cf7d04SAleksandr Rybalko { 30527cf7d04SAleksandr Rybalko 30627cf7d04SAleksandr Rybalko *r = vb->vb_dirtyrect; 30727cf7d04SAleksandr Rybalko vtbuf_make_undirty(vb); 30827cf7d04SAleksandr Rybalko } 30927cf7d04SAleksandr Rybalko 31027cf7d04SAleksandr Rybalko void 31127cf7d04SAleksandr Rybalko vtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 31227cf7d04SAleksandr Rybalko { 31327cf7d04SAleksandr Rybalko const term_pos_t *p1 = &r->tr_begin; 31427cf7d04SAleksandr Rybalko term_rect_t area; 31527cf7d04SAleksandr Rybalko unsigned int rows, cols; 31627cf7d04SAleksandr Rybalko int pr, rdiff; 31727cf7d04SAleksandr Rybalko 31827cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 31927cf7d04SAleksandr Rybalko ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 32027cf7d04SAleksandr Rybalko r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 32127cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 32227cf7d04SAleksandr Rybalko ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 32327cf7d04SAleksandr Rybalko r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 32427cf7d04SAleksandr Rybalko 32527cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 32627cf7d04SAleksandr Rybalko ("vtbuf_copy end.tp_row %d must be less than screen width %d", 32727cf7d04SAleksandr Rybalko r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 32827cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 32927cf7d04SAleksandr Rybalko ("vtbuf_copy end.tp_col %d must be less than screen height %d", 33027cf7d04SAleksandr Rybalko r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 33127cf7d04SAleksandr Rybalko 33227cf7d04SAleksandr Rybalko KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 33327cf7d04SAleksandr Rybalko ("vtbuf_copy tp_row %d must be less than screen width %d", 33427cf7d04SAleksandr Rybalko p2->tp_row, vb->vb_scr_size.tp_row)); 33527cf7d04SAleksandr Rybalko KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 33627cf7d04SAleksandr Rybalko ("vtbuf_copy tp_col %d must be less than screen height %d", 33727cf7d04SAleksandr Rybalko p2->tp_col, vb->vb_scr_size.tp_col)); 33827cf7d04SAleksandr Rybalko 33927cf7d04SAleksandr Rybalko rows = r->tr_end.tp_row - r->tr_begin.tp_row; 34027cf7d04SAleksandr Rybalko rdiff = r->tr_begin.tp_row - p2->tp_row; 34127cf7d04SAleksandr Rybalko cols = r->tr_end.tp_col - r->tr_begin.tp_col; 34227cf7d04SAleksandr Rybalko if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 34327cf7d04SAleksandr Rybalko r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 34427cf7d04SAleksandr Rybalko (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 34513c6f8a0SAleksandr Rybalko rdiff > 0) { /* Only forward direction. Do not eat history. */ 34627cf7d04SAleksandr Rybalko vthistory_addlines(vb, rdiff); 34727cf7d04SAleksandr Rybalko } else if (p2->tp_row < p1->tp_row) { 34827cf7d04SAleksandr Rybalko /* Handle overlapping copies of line segments. */ 34927cf7d04SAleksandr Rybalko /* Move data up. */ 35027cf7d04SAleksandr Rybalko for (pr = 0; pr < rows; pr++) 35127cf7d04SAleksandr Rybalko memmove( 35227cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 35327cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 35427cf7d04SAleksandr Rybalko cols * sizeof(term_char_t)); 35527cf7d04SAleksandr Rybalko } else { 35627cf7d04SAleksandr Rybalko /* Move data down. */ 35727cf7d04SAleksandr Rybalko for (pr = rows - 1; pr >= 0; pr--) 35827cf7d04SAleksandr Rybalko memmove( 35927cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 36027cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 36127cf7d04SAleksandr Rybalko cols * sizeof(term_char_t)); 36227cf7d04SAleksandr Rybalko } 36327cf7d04SAleksandr Rybalko 36427cf7d04SAleksandr Rybalko area.tr_begin = *p2; 36527cf7d04SAleksandr Rybalko area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 36627cf7d04SAleksandr Rybalko area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 36727cf7d04SAleksandr Rybalko vtbuf_dirty(vb, &area); 36827cf7d04SAleksandr Rybalko } 36927cf7d04SAleksandr Rybalko 37027cf7d04SAleksandr Rybalko static void 371547e74a8SJean-Sébastien Pédron vtbuf_do_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 37227cf7d04SAleksandr Rybalko { 37327cf7d04SAleksandr Rybalko unsigned int pr, pc; 37427cf7d04SAleksandr Rybalko term_char_t *row; 37527cf7d04SAleksandr Rybalko 37627cf7d04SAleksandr Rybalko for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 37727cf7d04SAleksandr Rybalko row = vb->vb_rows[(vb->vb_curroffset + pr) % 37827cf7d04SAleksandr Rybalko VTBUF_MAX_HEIGHT(vb)]; 37927cf7d04SAleksandr Rybalko for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 38027cf7d04SAleksandr Rybalko row[pc] = c; 38127cf7d04SAleksandr Rybalko } 38227cf7d04SAleksandr Rybalko } 38327cf7d04SAleksandr Rybalko } 38427cf7d04SAleksandr Rybalko 38527cf7d04SAleksandr Rybalko void 386547e74a8SJean-Sébastien Pédron vtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 38727cf7d04SAleksandr Rybalko { 388547e74a8SJean-Sébastien Pédron 38927cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 390547e74a8SJean-Sébastien Pédron ("vtbuf_fill begin.tp_row %d must be < screen height %d", 39127cf7d04SAleksandr Rybalko r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 39227cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 393547e74a8SJean-Sébastien Pédron ("vtbuf_fill begin.tp_col %d must be < screen width %d", 39427cf7d04SAleksandr Rybalko r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 39527cf7d04SAleksandr Rybalko 39627cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 397547e74a8SJean-Sébastien Pédron ("vtbuf_fill end.tp_row %d must be <= screen height %d", 39827cf7d04SAleksandr Rybalko r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 39927cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 400547e74a8SJean-Sébastien Pédron ("vtbuf_fill end.tp_col %d must be <= screen width %d", 40127cf7d04SAleksandr Rybalko r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 40227cf7d04SAleksandr Rybalko 403547e74a8SJean-Sébastien Pédron vtbuf_do_fill(vb, r, c); 404547e74a8SJean-Sébastien Pédron vtbuf_dirty(vb, r); 40527cf7d04SAleksandr Rybalko } 40627cf7d04SAleksandr Rybalko 40727cf7d04SAleksandr Rybalko static void 40827cf7d04SAleksandr Rybalko vtbuf_init_rows(struct vt_buf *vb) 40927cf7d04SAleksandr Rybalko { 41027cf7d04SAleksandr Rybalko int r; 41127cf7d04SAleksandr Rybalko 41227cf7d04SAleksandr Rybalko vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 41327cf7d04SAleksandr Rybalko 41427cf7d04SAleksandr Rybalko for (r = 0; r < vb->vb_history_size; r++) 4157344ee18SMarius Strobl vb->vb_rows[r] = &vb->vb_buffer[r * vb->vb_scr_size.tp_col]; 41627cf7d04SAleksandr Rybalko } 41727cf7d04SAleksandr Rybalko 41898f7cf02SJason A. Harmening static void 41998f7cf02SJason A. Harmening vtbuf_do_clearhistory(struct vt_buf *vb) 42027cf7d04SAleksandr Rybalko { 4217344ee18SMarius Strobl term_rect_t rect; 422df1bc27aSToomas Soome const teken_attr_t *a; 42398f7cf02SJason A. Harmening term_char_t ch; 42427cf7d04SAleksandr Rybalko 42598f7cf02SJason A. Harmening a = teken_get_curattr(&vb->vb_terminal->tm_emulator); 42698f7cf02SJason A. Harmening ch = TCOLOR_FG(a->ta_fgcolor) | TCOLOR_BG(a->ta_bgcolor); 42798f7cf02SJason A. Harmening 42898f7cf02SJason A. Harmening rect.tr_begin.tp_row = rect.tr_begin.tp_col = 0; 42998f7cf02SJason A. Harmening rect.tr_end.tp_col = vb->vb_scr_size.tp_col; 43098f7cf02SJason A. Harmening rect.tr_end.tp_row = vb->vb_history_size; 43198f7cf02SJason A. Harmening 43298f7cf02SJason A. Harmening vtbuf_do_fill(vb, &rect, VTBUF_SPACE_CHAR(ch)); 43398f7cf02SJason A. Harmening } 43498f7cf02SJason A. Harmening 435ef1eabcaSJason A. Harmening static void 436ef1eabcaSJason A. Harmening vtbuf_reset_scrollback(struct vt_buf *vb) 43798f7cf02SJason A. Harmening { 43827cf7d04SAleksandr Rybalko vb->vb_roffset = 0; 43927cf7d04SAleksandr Rybalko vb->vb_curroffset = 0; 44027cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = 0; 44127cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = 0; 44227cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = 0; 44327cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = 0; 444ef1eabcaSJason A. Harmening } 44527cf7d04SAleksandr Rybalko 446ef1eabcaSJason A. Harmening void 447ef1eabcaSJason A. Harmening vtbuf_init_early(struct vt_buf *vb) 448ef1eabcaSJason A. Harmening { 449ef1eabcaSJason A. Harmening vb->vb_flags |= VBF_CURSOR; 450ef1eabcaSJason A. Harmening vtbuf_reset_scrollback(vb); 45127cf7d04SAleksandr Rybalko vtbuf_init_rows(vb); 45298f7cf02SJason A. Harmening vtbuf_do_clearhistory(vb); 45327cf7d04SAleksandr Rybalko vtbuf_make_undirty(vb); 45427cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 45527cf7d04SAleksandr Rybalko mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 45627cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_MTX_INIT; 45727cf7d04SAleksandr Rybalko } 45827cf7d04SAleksandr Rybalko } 45927cf7d04SAleksandr Rybalko 46027cf7d04SAleksandr Rybalko void 46127cf7d04SAleksandr Rybalko vtbuf_init(struct vt_buf *vb, const term_pos_t *p) 46227cf7d04SAleksandr Rybalko { 46327cf7d04SAleksandr Rybalko int sz; 46427cf7d04SAleksandr Rybalko 46527cf7d04SAleksandr Rybalko vb->vb_scr_size = *p; 46627cf7d04SAleksandr Rybalko vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 46727cf7d04SAleksandr Rybalko 46827cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_STATIC) == 0) { 46927cf7d04SAleksandr Rybalko sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 47027cf7d04SAleksandr Rybalko vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 47127cf7d04SAleksandr Rybalko 47227cf7d04SAleksandr Rybalko sz = vb->vb_history_size * sizeof(term_char_t *); 47327cf7d04SAleksandr Rybalko vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 47427cf7d04SAleksandr Rybalko } 47527cf7d04SAleksandr Rybalko 47627cf7d04SAleksandr Rybalko vtbuf_init_early(vb); 47727cf7d04SAleksandr Rybalko } 47827cf7d04SAleksandr Rybalko 47927cf7d04SAleksandr Rybalko void 48098f7cf02SJason A. Harmening vtbuf_clearhistory(struct vt_buf *vb) 48198f7cf02SJason A. Harmening { 48298f7cf02SJason A. Harmening VTBUF_LOCK(vb); 48398f7cf02SJason A. Harmening vtbuf_do_clearhistory(vb); 484ef1eabcaSJason A. Harmening vtbuf_reset_scrollback(vb); 485ef1eabcaSJason A. Harmening vb->vb_flags &= ~VBF_HISTORY_FULL; 48698f7cf02SJason A. Harmening VTBUF_UNLOCK(vb); 48798f7cf02SJason A. Harmening } 48898f7cf02SJason A. Harmening 48998f7cf02SJason A. Harmening void 490e1734edfSEd Maste vtbuf_sethistory_size(struct vt_buf *vb, unsigned int size) 49127cf7d04SAleksandr Rybalko { 49227cf7d04SAleksandr Rybalko term_pos_t p; 49327cf7d04SAleksandr Rybalko 49427cf7d04SAleksandr Rybalko /* With same size */ 49527cf7d04SAleksandr Rybalko p.tp_row = vb->vb_scr_size.tp_row; 49627cf7d04SAleksandr Rybalko p.tp_col = vb->vb_scr_size.tp_col; 49727cf7d04SAleksandr Rybalko vtbuf_grow(vb, &p, size); 49827cf7d04SAleksandr Rybalko } 49927cf7d04SAleksandr Rybalko 50027cf7d04SAleksandr Rybalko void 501b7fe4961SJean-Sébastien Pédron vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size) 50227cf7d04SAleksandr Rybalko { 5031454439cSJean-Sébastien Pédron term_char_t *old, *new, **rows, **oldrows, **copyrows, *row, *oldrow; 504e1734edfSEd Maste unsigned int w, h, c, r, old_history_size; 505e1734edfSEd Maste size_t bufsize, rowssize; 506e1734edfSEd Maste int history_full; 507df1bc27aSToomas Soome const teken_attr_t *a; 508df1bc27aSToomas Soome term_char_t ch; 509df1bc27aSToomas Soome 510df1bc27aSToomas Soome a = teken_get_curattr(&vb->vb_terminal->tm_emulator); 511df1bc27aSToomas Soome ch = TCOLOR_FG(a->ta_fgcolor) | TCOLOR_BG(a->ta_bgcolor); 51227cf7d04SAleksandr Rybalko 51327cf7d04SAleksandr Rybalko history_size = MAX(history_size, p->tp_row); 51427cf7d04SAleksandr Rybalko 51527cf7d04SAleksandr Rybalko /* Allocate new buffer. */ 51627cf7d04SAleksandr Rybalko bufsize = history_size * p->tp_col * sizeof(term_char_t); 51727cf7d04SAleksandr Rybalko new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 51827cf7d04SAleksandr Rybalko rowssize = history_size * sizeof(term_pos_t *); 51927cf7d04SAleksandr Rybalko rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 52027cf7d04SAleksandr Rybalko 52127cf7d04SAleksandr Rybalko /* Toggle it. */ 52227cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 52327cf7d04SAleksandr Rybalko old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 52427cf7d04SAleksandr Rybalko oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 52527cf7d04SAleksandr Rybalko copyrows = vb->vb_rows; 5261454439cSJean-Sébastien Pédron 52727cf7d04SAleksandr Rybalko w = vb->vb_scr_size.tp_col; 5281454439cSJean-Sébastien Pédron h = vb->vb_scr_size.tp_row; 5291454439cSJean-Sébastien Pédron old_history_size = vb->vb_history_size; 530e1734edfSEd Maste history_full = vb->vb_flags & VBF_HISTORY_FULL || 531e1734edfSEd Maste vb->vb_curroffset + h >= history_size; 53227cf7d04SAleksandr Rybalko 53327cf7d04SAleksandr Rybalko vb->vb_history_size = history_size; 53427cf7d04SAleksandr Rybalko vb->vb_buffer = new; 53527cf7d04SAleksandr Rybalko vb->vb_rows = rows; 53627cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_STATIC; 53727cf7d04SAleksandr Rybalko vb->vb_scr_size = *p; 53827cf7d04SAleksandr Rybalko vtbuf_init_rows(vb); 53927cf7d04SAleksandr Rybalko 5401454439cSJean-Sébastien Pédron /* 5411454439cSJean-Sébastien Pédron * Copy rows to the new buffer. The first row in the history 5421454439cSJean-Sébastien Pédron * is back to index 0, ie. the new buffer doesn't cycle. 5431454439cSJean-Sébastien Pédron */ 544e1734edfSEd Maste if (history_size > old_history_size) { 5451454439cSJean-Sébastien Pédron for (r = 0; r < old_history_size; r++) { 5461454439cSJean-Sébastien Pédron row = rows[r]; 5471454439cSJean-Sébastien Pédron 5481454439cSJean-Sébastien Pédron /* Compute the corresponding row in the old buffer. */ 549e1734edfSEd Maste if (history_full) 5501454439cSJean-Sébastien Pédron /* 5511454439cSJean-Sébastien Pédron * The buffer is full, the "top" row is 5521454439cSJean-Sébastien Pédron * the one just after the viewable area 5531454439cSJean-Sébastien Pédron * (curroffset + viewable height) in the 5541454439cSJean-Sébastien Pédron * cycling buffer. The corresponding row 5551454439cSJean-Sébastien Pédron * is computed from this top row. 5561454439cSJean-Sébastien Pédron */ 5571454439cSJean-Sébastien Pédron oldrow = copyrows[ 5581454439cSJean-Sébastien Pédron (vb->vb_curroffset + h + r) % 5591454439cSJean-Sébastien Pédron old_history_size]; 5601454439cSJean-Sébastien Pédron else 5611454439cSJean-Sébastien Pédron /* 5621454439cSJean-Sébastien Pédron * The buffer is not full, therefore, 5631454439cSJean-Sébastien Pédron * we didn't cycle already. The 5641454439cSJean-Sébastien Pédron * corresponding rows are the same in 5651454439cSJean-Sébastien Pédron * both buffers. 5661454439cSJean-Sébastien Pédron */ 5671454439cSJean-Sébastien Pédron oldrow = copyrows[r]; 5681454439cSJean-Sébastien Pédron 5691454439cSJean-Sébastien Pédron memmove(row, oldrow, 5701454439cSJean-Sébastien Pédron MIN(p->tp_col, w) * sizeof(term_char_t)); 5711454439cSJean-Sébastien Pédron 5727344ee18SMarius Strobl /* 5737344ee18SMarius Strobl * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 5747344ee18SMarius Strobl * extended lines of kernel text using the wrong 5757344ee18SMarius Strobl * background color. 5767344ee18SMarius Strobl */ 5771454439cSJean-Sébastien Pédron for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 578df1bc27aSToomas Soome row[c] = VTBUF_SPACE_CHAR(ch); 57927cf7d04SAleksandr Rybalko } 5801454439cSJean-Sébastien Pédron } 5811454439cSJean-Sébastien Pédron 5821454439cSJean-Sébastien Pédron /* Fill remaining rows. */ 583e1734edfSEd Maste for (r = old_history_size; r < history_size; r++) { 584e1734edfSEd Maste row = rows[r]; 585e1734edfSEd Maste for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 586df1bc27aSToomas Soome row[c] = VTBUF_SPACE_CHAR(ch); 587e1734edfSEd Maste } 588e1734edfSEd Maste } 5891454439cSJean-Sébastien Pédron 5901454439cSJean-Sébastien Pédron vb->vb_flags &= ~VBF_HISTORY_FULL; 591e1734edfSEd Maste 592e1734edfSEd Maste /* 593e1734edfSEd Maste * If the screen is already filled (there are non-visible lines 594e1734edfSEd Maste * above the current viewable area), adjust curroffset to the 595e1734edfSEd Maste * new viewable area. 596e1734edfSEd Maste * 597e1734edfSEd Maste * If the old buffer was full, set curroffset to the 598e1734edfSEd Maste * <h>th most recent line of history in the new, non-cycled 599e1734edfSEd Maste * buffer. Otherwise, it didn't cycle, so the old curroffset 600e1734edfSEd Maste * is the same in the new buffer. 601e1734edfSEd Maste */ 602e1734edfSEd Maste if (history_full) 603e1734edfSEd Maste vb->vb_curroffset = old_history_size - h; 6041454439cSJean-Sébastien Pédron } else { 6051454439cSJean-Sébastien Pédron /* 6061454439cSJean-Sébastien Pédron * (old_history_size - history_size) lines of history are 6071454439cSJean-Sébastien Pédron * dropped. 6081454439cSJean-Sébastien Pédron */ 6091454439cSJean-Sébastien Pédron for (r = 0; r < history_size; r++) { 6101454439cSJean-Sébastien Pédron row = rows[r]; 6111454439cSJean-Sébastien Pédron 6121454439cSJean-Sébastien Pédron /* 6131454439cSJean-Sébastien Pédron * Compute the corresponding row in the old buffer. 6141454439cSJean-Sébastien Pédron * 6151454439cSJean-Sébastien Pédron * See the equivalent if{} block above for an 6161454439cSJean-Sébastien Pédron * explanation. 6171454439cSJean-Sébastien Pédron */ 618e1734edfSEd Maste if (history_full) 6191454439cSJean-Sébastien Pédron oldrow = copyrows[ 6201454439cSJean-Sébastien Pédron (vb->vb_curroffset + h + r + 6211454439cSJean-Sébastien Pédron (old_history_size - history_size)) % 6221454439cSJean-Sébastien Pédron old_history_size]; 6231454439cSJean-Sébastien Pédron else 624e1734edfSEd Maste oldrow = copyrows[r]; 6251454439cSJean-Sébastien Pédron 6261454439cSJean-Sébastien Pédron memmove(row, oldrow, 6271454439cSJean-Sébastien Pédron MIN(p->tp_col, w) * sizeof(term_char_t)); 6281454439cSJean-Sébastien Pédron 6291454439cSJean-Sébastien Pédron /* 6301454439cSJean-Sébastien Pédron * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 6311454439cSJean-Sébastien Pédron * extended lines of kernel text using the wrong 6321454439cSJean-Sébastien Pédron * background color. 6331454439cSJean-Sébastien Pédron */ 6341454439cSJean-Sébastien Pédron for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 635df1bc27aSToomas Soome row[c] = VTBUF_SPACE_CHAR(ch); 63627cf7d04SAleksandr Rybalko } 63727cf7d04SAleksandr Rybalko } 6381454439cSJean-Sébastien Pédron 639e1734edfSEd Maste if (history_full) { 640e1734edfSEd Maste vb->vb_curroffset = history_size - h; 6411454439cSJean-Sébastien Pédron vb->vb_flags |= VBF_HISTORY_FULL; 6421454439cSJean-Sébastien Pédron } 6431454439cSJean-Sébastien Pédron } 6441454439cSJean-Sébastien Pédron 645e1734edfSEd Maste vb->vb_roffset = vb->vb_curroffset; 646e1734edfSEd Maste 647da49f6bcSJean-Sébastien Pédron /* Adjust cursor position. */ 648da49f6bcSJean-Sébastien Pédron if (vb->vb_cursor.tp_col > p->tp_col - 1) 649da49f6bcSJean-Sébastien Pédron /* 650da49f6bcSJean-Sébastien Pédron * Move cursor to the last column, in case its previous 651da49f6bcSJean-Sébastien Pédron * position is outside of the new screen area. 652da49f6bcSJean-Sébastien Pédron */ 653da49f6bcSJean-Sébastien Pédron vb->vb_cursor.tp_col = p->tp_col - 1; 654da49f6bcSJean-Sébastien Pédron 655da49f6bcSJean-Sébastien Pédron if (vb->vb_curroffset > 0 || vb->vb_cursor.tp_row > p->tp_row - 1) 656da49f6bcSJean-Sébastien Pédron /* Move cursor to the last line on the screen. */ 657da49f6bcSJean-Sébastien Pédron vb->vb_cursor.tp_row = p->tp_row - 1; 658da49f6bcSJean-Sébastien Pédron 65927cf7d04SAleksandr Rybalko VTBUF_UNLOCK(vb); 6601454439cSJean-Sébastien Pédron 66127cf7d04SAleksandr Rybalko /* Deallocate old buffer. */ 66227cf7d04SAleksandr Rybalko free(old, M_VTBUF); 66327cf7d04SAleksandr Rybalko free(oldrows, M_VTBUF); 66427cf7d04SAleksandr Rybalko } 66527cf7d04SAleksandr Rybalko 66627cf7d04SAleksandr Rybalko void 66727cf7d04SAleksandr Rybalko vtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 66827cf7d04SAleksandr Rybalko { 66927cf7d04SAleksandr Rybalko term_char_t *row; 67027cf7d04SAleksandr Rybalko 67127cf7d04SAleksandr Rybalko KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 67227cf7d04SAleksandr Rybalko ("vtbuf_putchar tp_row %d must be less than screen width %d", 67327cf7d04SAleksandr Rybalko p->tp_row, vb->vb_scr_size.tp_row)); 67427cf7d04SAleksandr Rybalko KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 67527cf7d04SAleksandr Rybalko ("vtbuf_putchar tp_col %d must be less than screen height %d", 67627cf7d04SAleksandr Rybalko p->tp_col, vb->vb_scr_size.tp_col)); 67727cf7d04SAleksandr Rybalko 67827cf7d04SAleksandr Rybalko row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 67927cf7d04SAleksandr Rybalko VTBUF_MAX_HEIGHT(vb)]; 68027cf7d04SAleksandr Rybalko if (row[p->tp_col] != c) { 68127cf7d04SAleksandr Rybalko row[p->tp_col] = c; 682547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, p); 68327cf7d04SAleksandr Rybalko } 68427cf7d04SAleksandr Rybalko } 68527cf7d04SAleksandr Rybalko 68627cf7d04SAleksandr Rybalko void 68727cf7d04SAleksandr Rybalko vtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 68827cf7d04SAleksandr Rybalko { 68927cf7d04SAleksandr Rybalko if (vb->vb_flags & VBF_CURSOR) { 690547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 69127cf7d04SAleksandr Rybalko vb->vb_cursor = *p; 692547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 69327cf7d04SAleksandr Rybalko } else { 69427cf7d04SAleksandr Rybalko vb->vb_cursor = *p; 69527cf7d04SAleksandr Rybalko } 69627cf7d04SAleksandr Rybalko } 69727cf7d04SAleksandr Rybalko 6980f49db6eSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 69927cf7d04SAleksandr Rybalko static void 70027cf7d04SAleksandr Rybalko vtbuf_flush_mark(struct vt_buf *vb) 70127cf7d04SAleksandr Rybalko { 70227cf7d04SAleksandr Rybalko term_rect_t area; 70327cf7d04SAleksandr Rybalko int s, e; 70427cf7d04SAleksandr Rybalko 70527cf7d04SAleksandr Rybalko /* Notify renderer to update marked region. */ 706c0e295deSAleksandr Rybalko if ((vb->vb_mark_start.tp_col != vb->vb_mark_end.tp_col) || 707c0e295deSAleksandr Rybalko (vb->vb_mark_start.tp_row != vb->vb_mark_end.tp_row)) { 70827cf7d04SAleksandr Rybalko s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 70927cf7d04SAleksandr Rybalko e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 71027cf7d04SAleksandr Rybalko 71127cf7d04SAleksandr Rybalko area.tr_begin.tp_col = 0; 71227cf7d04SAleksandr Rybalko area.tr_begin.tp_row = MIN(s, e); 71327cf7d04SAleksandr Rybalko 71427cf7d04SAleksandr Rybalko area.tr_end.tp_col = vb->vb_scr_size.tp_col; 71527cf7d04SAleksandr Rybalko area.tr_end.tp_row = MAX(s, e) + 1; 71627cf7d04SAleksandr Rybalko 717547e74a8SJean-Sébastien Pédron VTBUF_LOCK(vb); 71827cf7d04SAleksandr Rybalko vtbuf_dirty(vb, &area); 719547e74a8SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 72027cf7d04SAleksandr Rybalko } 72127cf7d04SAleksandr Rybalko } 72227cf7d04SAleksandr Rybalko 72327cf7d04SAleksandr Rybalko int 72427cf7d04SAleksandr Rybalko vtbuf_get_marked_len(struct vt_buf *vb) 72527cf7d04SAleksandr Rybalko { 72627cf7d04SAleksandr Rybalko int ei, si, sz; 72727cf7d04SAleksandr Rybalko term_pos_t s, e; 72827cf7d04SAleksandr Rybalko 72927cf7d04SAleksandr Rybalko /* Swap according to window coordinates. */ 73027cf7d04SAleksandr Rybalko if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 73127cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col) > 73227cf7d04SAleksandr Rybalko POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 73327cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col)) { 73427cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_start); 73527cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_end); 73627cf7d04SAleksandr Rybalko } else { 73727cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_start); 73827cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_end); 73927cf7d04SAleksandr Rybalko } 74027cf7d04SAleksandr Rybalko 74127cf7d04SAleksandr Rybalko si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 74227cf7d04SAleksandr Rybalko ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 74327cf7d04SAleksandr Rybalko 74427cf7d04SAleksandr Rybalko /* Number symbols and number of rows to inject \n */ 74544f751a2SAleksandr Rybalko sz = ei - si + ((e.tp_row - s.tp_row) * 2); 74627cf7d04SAleksandr Rybalko 74727cf7d04SAleksandr Rybalko return (sz * sizeof(term_char_t)); 74827cf7d04SAleksandr Rybalko } 74927cf7d04SAleksandr Rybalko 75027cf7d04SAleksandr Rybalko void 75127cf7d04SAleksandr Rybalko vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 75227cf7d04SAleksandr Rybalko { 75327cf7d04SAleksandr Rybalko int i, r, c, cs, ce; 75427cf7d04SAleksandr Rybalko term_pos_t s, e; 75527cf7d04SAleksandr Rybalko 75627cf7d04SAleksandr Rybalko /* Swap according to window coordinates. */ 75727cf7d04SAleksandr Rybalko if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 75827cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col) > 75927cf7d04SAleksandr Rybalko POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 76027cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col)) { 76127cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_start); 76227cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_end); 76327cf7d04SAleksandr Rybalko } else { 76427cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_start); 76527cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_end); 76627cf7d04SAleksandr Rybalko } 76727cf7d04SAleksandr Rybalko 76827cf7d04SAleksandr Rybalko i = 0; 76927cf7d04SAleksandr Rybalko for (r = s.tp_row; r <= e.tp_row; r++) { 77027cf7d04SAleksandr Rybalko cs = (r == s.tp_row)?s.tp_col:0; 77127cf7d04SAleksandr Rybalko ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 77227cf7d04SAleksandr Rybalko for (c = cs; c < ce; c++) { 77327cf7d04SAleksandr Rybalko buf[i++] = vb->vb_rows[r][c]; 77427cf7d04SAleksandr Rybalko } 77527cf7d04SAleksandr Rybalko /* Add new line for all rows, but not for last one. */ 77627cf7d04SAleksandr Rybalko if (r != e.tp_row) { 77727cf7d04SAleksandr Rybalko buf[i++] = '\r'; 77827cf7d04SAleksandr Rybalko buf[i++] = '\n'; 77927cf7d04SAleksandr Rybalko } 78027cf7d04SAleksandr Rybalko } 78127cf7d04SAleksandr Rybalko } 78227cf7d04SAleksandr Rybalko 78327cf7d04SAleksandr Rybalko int 78427cf7d04SAleksandr Rybalko vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 78527cf7d04SAleksandr Rybalko { 78627cf7d04SAleksandr Rybalko term_char_t *r; 78727cf7d04SAleksandr Rybalko int i; 78827cf7d04SAleksandr Rybalko 78927cf7d04SAleksandr Rybalko switch (type) { 79027cf7d04SAleksandr Rybalko case VTB_MARK_END: /* B1 UP */ 79127cf7d04SAleksandr Rybalko if (vb->vb_mark_last != VTB_MARK_MOVE) 79227cf7d04SAleksandr Rybalko return (0); 79327cf7d04SAleksandr Rybalko /* FALLTHROUGH */ 79427cf7d04SAleksandr Rybalko case VTB_MARK_MOVE: 79527cf7d04SAleksandr Rybalko case VTB_MARK_EXTEND: 79627cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 79727cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = col; 79827cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 79927cf7d04SAleksandr Rybalko break; 80027cf7d04SAleksandr Rybalko case VTB_MARK_START: 80127cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 80227cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = col; 80327cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 80427cf7d04SAleksandr Rybalko /* Start again, so clear end point. */ 80527cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = col; 80627cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 80727cf7d04SAleksandr Rybalko break; 80827cf7d04SAleksandr Rybalko case VTB_MARK_WORD: 80927cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 81027cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 81127cf7d04SAleksandr Rybalko vtbuf_wth(vb, row); 81227cf7d04SAleksandr Rybalko r = vb->vb_rows[vb->vb_mark_start.tp_row]; 81327cf7d04SAleksandr Rybalko for (i = col; i >= 0; i --) { 81427cf7d04SAleksandr Rybalko if (TCHAR_CHARACTER(r[i]) == ' ') { 81527cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = i + 1; 81627cf7d04SAleksandr Rybalko break; 81727cf7d04SAleksandr Rybalko } 81827cf7d04SAleksandr Rybalko } 819692bb3f0SEd Maste /* No space - word extends to beginning of line. */ 820692bb3f0SEd Maste if (i == -1) 821692bb3f0SEd Maste vb->vb_mark_start.tp_col = 0; 82227cf7d04SAleksandr Rybalko for (i = col; i < vb->vb_scr_size.tp_col; i++) { 82327cf7d04SAleksandr Rybalko if (TCHAR_CHARACTER(r[i]) == ' ') { 82427cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = i; 82527cf7d04SAleksandr Rybalko break; 82627cf7d04SAleksandr Rybalko } 82727cf7d04SAleksandr Rybalko } 82827cf7d04SAleksandr Rybalko if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col) 82927cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 83027cf7d04SAleksandr Rybalko break; 83127cf7d04SAleksandr Rybalko case VTB_MARK_ROW: 83227cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 83327cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = 0; 83427cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 83527cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 83627cf7d04SAleksandr Rybalko vtbuf_wth(vb, row); 83727cf7d04SAleksandr Rybalko break; 83827cf7d04SAleksandr Rybalko case VTB_MARK_NONE: 83927cf7d04SAleksandr Rybalko vb->vb_mark_last = type; 84027cf7d04SAleksandr Rybalko /* FALLTHROUGH */ 84127cf7d04SAleksandr Rybalko default: 84227cf7d04SAleksandr Rybalko /* panic? */ 84327cf7d04SAleksandr Rybalko return (0); 84427cf7d04SAleksandr Rybalko } 84527cf7d04SAleksandr Rybalko 84627cf7d04SAleksandr Rybalko vb->vb_mark_last = type; 84727cf7d04SAleksandr Rybalko /* Draw new marked region. */ 84827cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); 84927cf7d04SAleksandr Rybalko return (1); 85027cf7d04SAleksandr Rybalko } 8510f49db6eSAleksandr Rybalko #endif 85227cf7d04SAleksandr Rybalko 85327cf7d04SAleksandr Rybalko void 85427cf7d04SAleksandr Rybalko vtbuf_cursor_visibility(struct vt_buf *vb, int yes) 85527cf7d04SAleksandr Rybalko { 85627cf7d04SAleksandr Rybalko int oflags, nflags; 85727cf7d04SAleksandr Rybalko 85827cf7d04SAleksandr Rybalko oflags = vb->vb_flags; 85927cf7d04SAleksandr Rybalko if (yes) 86027cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_CURSOR; 86127cf7d04SAleksandr Rybalko else 86227cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_CURSOR; 86327cf7d04SAleksandr Rybalko nflags = vb->vb_flags; 86427cf7d04SAleksandr Rybalko 86527cf7d04SAleksandr Rybalko if (oflags != nflags) 866547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 86727cf7d04SAleksandr Rybalko } 86827cf7d04SAleksandr Rybalko 86927cf7d04SAleksandr Rybalko void 87027cf7d04SAleksandr Rybalko vtbuf_scroll_mode(struct vt_buf *vb, int yes) 87127cf7d04SAleksandr Rybalko { 87227cf7d04SAleksandr Rybalko int oflags, nflags; 87327cf7d04SAleksandr Rybalko 87427cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 87527cf7d04SAleksandr Rybalko oflags = vb->vb_flags; 87627cf7d04SAleksandr Rybalko if (yes) 87727cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_SCROLL; 87827cf7d04SAleksandr Rybalko else 87927cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_SCROLL; 88027cf7d04SAleksandr Rybalko nflags = vb->vb_flags; 88127cf7d04SAleksandr Rybalko 88227cf7d04SAleksandr Rybalko if (oflags != nflags) 883547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 88400c33067SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 88527cf7d04SAleksandr Rybalko } 886