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 * All rights reserved. 627cf7d04SAleksandr Rybalko * 727cf7d04SAleksandr Rybalko * This software was developed by Ed Schouten under sponsorship from the 827cf7d04SAleksandr Rybalko * FreeBSD Foundation. 927cf7d04SAleksandr Rybalko * 1027cf7d04SAleksandr Rybalko * Portions of this software were developed by Oleksandr Rybalko 1127cf7d04SAleksandr Rybalko * under sponsorship from the FreeBSD Foundation. 1227cf7d04SAleksandr Rybalko * 1327cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 1427cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 1527cf7d04SAleksandr Rybalko * are met: 1627cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1727cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1827cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1927cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 2027cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 2127cf7d04SAleksandr Rybalko * 2227cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2327cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2427cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2527cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2627cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2727cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2827cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2927cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3027cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3127cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3227cf7d04SAleksandr Rybalko * SUCH DAMAGE. 3327cf7d04SAleksandr Rybalko */ 3427cf7d04SAleksandr Rybalko 3527cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 3627cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 3727cf7d04SAleksandr Rybalko 3827cf7d04SAleksandr Rybalko #include <sys/param.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 #include <sys/systm.h> 4527cf7d04SAleksandr Rybalko 4627cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 4727cf7d04SAleksandr Rybalko 4827cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); 4927cf7d04SAleksandr Rybalko 5027cf7d04SAleksandr Rybalko #define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) 5127cf7d04SAleksandr Rybalko #define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) 5227cf7d04SAleksandr Rybalko 5327cf7d04SAleksandr Rybalko #define POS_INDEX(c, r) (((r) << 12) + (c)) 5427cf7d04SAleksandr Rybalko #define POS_COPY(d, s) do { \ 5527cf7d04SAleksandr Rybalko (d).tp_col = (s).tp_col; \ 5627cf7d04SAleksandr Rybalko (d).tp_row = (s).tp_row; \ 5727cf7d04SAleksandr Rybalko } while (0) 5827cf7d04SAleksandr Rybalko 59c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 6007a45594SRavi Pokala static int vtbuf_htw(const struct vt_buf *vb, int row); 61c0e295deSAleksandr Rybalko static int vtbuf_wth(const struct vt_buf *vb, int row); 62c0e295deSAleksandr Rybalko static int vtbuf_in_this_range(int begin, int test, int end, int sz); 63c0e295deSAleksandr Rybalko #endif 6427cf7d04SAleksandr Rybalko 6527cf7d04SAleksandr Rybalko /* 6627cf7d04SAleksandr Rybalko * line4 6727cf7d04SAleksandr Rybalko * line5 <--- curroffset (terminal output to that line) 6827cf7d04SAleksandr Rybalko * line0 6927cf7d04SAleksandr Rybalko * line1 <--- roffset (history display from that point) 7027cf7d04SAleksandr Rybalko * line2 7127cf7d04SAleksandr Rybalko * line3 7227cf7d04SAleksandr Rybalko */ 7327cf7d04SAleksandr Rybalko int 7427cf7d04SAleksandr Rybalko vthistory_seek(struct vt_buf *vb, int offset, int whence) 7527cf7d04SAleksandr Rybalko { 7627cf7d04SAleksandr Rybalko int diff, top, bottom, roffset; 7727cf7d04SAleksandr Rybalko 7827cf7d04SAleksandr Rybalko /* No scrolling if not enabled. */ 7927cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_SCROLL) == 0) { 8027cf7d04SAleksandr Rybalko if (vb->vb_roffset != vb->vb_curroffset) { 8127cf7d04SAleksandr Rybalko vb->vb_roffset = vb->vb_curroffset; 8227cf7d04SAleksandr Rybalko return (0xffff); 8327cf7d04SAleksandr Rybalko } 8427cf7d04SAleksandr Rybalko return (0); /* No changes */ 8527cf7d04SAleksandr Rybalko } 8627cf7d04SAleksandr Rybalko 871454439cSJean-Sébastien Pédron /* "top" may be a negative integer. */ 881454439cSJean-Sébastien Pédron bottom = vb->vb_curroffset; 891454439cSJean-Sébastien Pédron top = (vb->vb_flags & VBF_HISTORY_FULL) ? 901454439cSJean-Sébastien Pédron bottom + vb->vb_scr_size.tp_row - vb->vb_history_size : 911454439cSJean-Sébastien Pédron 0; 921454439cSJean-Sébastien Pédron 93a10068fdSBjoern A. Zeeb roffset = 0; /* Make gcc happy. */ 9427cf7d04SAleksandr Rybalko switch (whence) { 9527cf7d04SAleksandr Rybalko case VHS_SET: 961454439cSJean-Sébastien Pédron if (offset < 0) 971454439cSJean-Sébastien Pédron offset = 0; 981454439cSJean-Sébastien Pédron roffset = top + offset; 9927cf7d04SAleksandr Rybalko break; 10027cf7d04SAleksandr Rybalko case VHS_CUR: 1011454439cSJean-Sébastien Pédron /* 1021454439cSJean-Sébastien Pédron * Operate on copy of offset value, since it temporary 1031454439cSJean-Sébastien Pédron * can be bigger than amount of rows in buffer. 1041454439cSJean-Sébastien Pédron */ 1051454439cSJean-Sébastien Pédron roffset = vb->vb_roffset; 1061454439cSJean-Sébastien Pédron if (roffset >= bottom + vb->vb_scr_size.tp_row) 1071454439cSJean-Sébastien Pédron roffset -= vb->vb_history_size; 1081454439cSJean-Sébastien Pédron 10927cf7d04SAleksandr Rybalko roffset += offset; 1101454439cSJean-Sébastien Pédron roffset = MAX(roffset, top); 1111454439cSJean-Sébastien Pédron roffset = MIN(roffset, bottom); 1121454439cSJean-Sébastien Pédron 1131454439cSJean-Sébastien Pédron if (roffset < 0) 1141454439cSJean-Sébastien Pédron roffset = vb->vb_history_size + roffset; 1151454439cSJean-Sébastien Pédron 11627cf7d04SAleksandr Rybalko break; 11727cf7d04SAleksandr Rybalko case VHS_END: 11827cf7d04SAleksandr Rybalko /* Go to current offset. */ 1191454439cSJean-Sébastien Pédron roffset = vb->vb_curroffset; 12027cf7d04SAleksandr Rybalko break; 12127cf7d04SAleksandr Rybalko } 12227cf7d04SAleksandr Rybalko 1231454439cSJean-Sébastien Pédron diff = vb->vb_roffset != roffset; 12427cf7d04SAleksandr Rybalko vb->vb_roffset = roffset; 1251454439cSJean-Sébastien Pédron 12627cf7d04SAleksandr Rybalko return (diff); 12727cf7d04SAleksandr Rybalko } 12827cf7d04SAleksandr Rybalko 12927cf7d04SAleksandr Rybalko void 13027cf7d04SAleksandr Rybalko vthistory_addlines(struct vt_buf *vb, int offset) 13127cf7d04SAleksandr Rybalko { 132c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 133c0e295deSAleksandr Rybalko int cur, sz; 134c0e295deSAleksandr Rybalko #endif 13527cf7d04SAleksandr Rybalko 13627cf7d04SAleksandr Rybalko vb->vb_curroffset += offset; 137e1734edfSEd Maste if (vb->vb_curroffset + vb->vb_scr_size.tp_row >= vb->vb_history_size) { 1381454439cSJean-Sébastien Pédron vb->vb_flags |= VBF_HISTORY_FULL; 13927cf7d04SAleksandr Rybalko vb->vb_curroffset %= vb->vb_history_size; 140e1734edfSEd Maste } 14127cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_SCROLL) == 0) { 14227cf7d04SAleksandr Rybalko vb->vb_roffset = vb->vb_curroffset; 14327cf7d04SAleksandr Rybalko } 144c0e295deSAleksandr Rybalko 145c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 146c0e295deSAleksandr Rybalko sz = vb->vb_history_size; 147c0e295deSAleksandr Rybalko cur = vb->vb_roffset + vb->vb_scr_size.tp_row + sz - 1; 148c0e295deSAleksandr Rybalko if (vtbuf_in_this_range(cur, vb->vb_mark_start.tp_row, cur + offset, sz) || 149c0e295deSAleksandr Rybalko vtbuf_in_this_range(cur, vb->vb_mark_end.tp_row, cur + offset, sz)) { 150c0e295deSAleksandr Rybalko /* clear screen selection */ 151c0e295deSAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row; 152c0e295deSAleksandr Rybalko vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 153c0e295deSAleksandr Rybalko } 154c0e295deSAleksandr Rybalko #endif 15527cf7d04SAleksandr Rybalko } 15627cf7d04SAleksandr Rybalko 15727cf7d04SAleksandr Rybalko void 15827cf7d04SAleksandr Rybalko vthistory_getpos(const struct vt_buf *vb, unsigned int *offset) 15927cf7d04SAleksandr Rybalko { 16027cf7d04SAleksandr Rybalko 16127cf7d04SAleksandr Rybalko *offset = vb->vb_roffset; 16227cf7d04SAleksandr Rybalko } 16327cf7d04SAleksandr Rybalko 1640f49db6eSAleksandr Rybalko #ifndef SC_NO_CUTPASTE /* Only mouse support use it now. */ 16507a45594SRavi Pokala /* Translate history row to current view row number. */ 16607a45594SRavi Pokala static int 16707a45594SRavi Pokala vtbuf_htw(const struct vt_buf *vb, int row) 16807a45594SRavi Pokala { 16907a45594SRavi Pokala 17007a45594SRavi Pokala /* 17107a45594SRavi Pokala * total 1000 rows. 17207a45594SRavi Pokala * History offset roffset winrow 17307a45594SRavi Pokala * 205 200 ((205 - 200 + 1000) % 1000) = 5 17407a45594SRavi Pokala * 90 990 ((90 - 990 + 1000) % 1000) = 100 17507a45594SRavi Pokala */ 17607a45594SRavi Pokala return ((row - vb->vb_roffset + vb->vb_history_size) % 17707a45594SRavi Pokala vb->vb_history_size); 17807a45594SRavi Pokala } 17907a45594SRavi Pokala 18027cf7d04SAleksandr Rybalko /* Translate current view row number to history row. */ 18127cf7d04SAleksandr Rybalko static int 182c0e295deSAleksandr Rybalko vtbuf_wth(const struct vt_buf *vb, int row) 18327cf7d04SAleksandr Rybalko { 18427cf7d04SAleksandr Rybalko 18527cf7d04SAleksandr Rybalko return ((vb->vb_roffset + row) % vb->vb_history_size); 18627cf7d04SAleksandr Rybalko } 187c0e295deSAleksandr Rybalko 188c0e295deSAleksandr Rybalko /* 189c0e295deSAleksandr Rybalko * Test if an index in a circular buffer is within a range. 190c0e295deSAleksandr Rybalko * 191c0e295deSAleksandr Rybalko * begin - start index 192c0e295deSAleksandr Rybalko * end - end index 193c0e295deSAleksandr Rybalko * test - test index 194c0e295deSAleksandr Rybalko * sz - size of circular buffer when it turns over 195c0e295deSAleksandr Rybalko */ 196c0e295deSAleksandr Rybalko static int 197c0e295deSAleksandr Rybalko vtbuf_in_this_range(int begin, int test, int end, int sz) 198c0e295deSAleksandr Rybalko { 199c0e295deSAleksandr Rybalko 200c0e295deSAleksandr Rybalko begin %= sz; 201c0e295deSAleksandr Rybalko end %= sz; 202c0e295deSAleksandr Rybalko 203c0e295deSAleksandr Rybalko /* check for inversion */ 204c0e295deSAleksandr Rybalko if (begin > end) 205c0e295deSAleksandr Rybalko return (test >= begin || test < end); 206c0e295deSAleksandr Rybalko else 207c0e295deSAleksandr Rybalko return (test >= begin && test < end); 208c0e295deSAleksandr Rybalko } 2090f49db6eSAleksandr Rybalko #endif 21027cf7d04SAleksandr Rybalko 21127cf7d04SAleksandr Rybalko int 212c6e1a987SJean-Sébastien Pédron vtbuf_iscursor(const struct vt_buf *vb, int row, int col) 21327cf7d04SAleksandr Rybalko { 214c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 215c0e295deSAleksandr Rybalko int sc, sr, sz, ec, er, tmp; 216c0e295deSAleksandr Rybalko #endif 21727cf7d04SAleksandr Rybalko 21827cf7d04SAleksandr Rybalko if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 21927cf7d04SAleksandr Rybalko (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 22027cf7d04SAleksandr Rybalko return (1); 22127cf7d04SAleksandr Rybalko 222c0e295deSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 22327cf7d04SAleksandr Rybalko /* Mark cut/paste region. */ 224c0e295deSAleksandr Rybalko if (vb->vb_mark_start.tp_col == vb->vb_mark_end.tp_col && 225c0e295deSAleksandr Rybalko vb->vb_mark_start.tp_row == vb->vb_mark_end.tp_row) 226c0e295deSAleksandr Rybalko return (0); 227c0e295deSAleksandr Rybalko 228c0e295deSAleksandr Rybalko sc = vb->vb_mark_start.tp_col; 229c0e295deSAleksandr Rybalko sr = vb->vb_mark_start.tp_row; 230c0e295deSAleksandr Rybalko ec = vb->vb_mark_end.tp_col; 231c0e295deSAleksandr Rybalko er = vb->vb_mark_end.tp_row; 23227cf7d04SAleksandr Rybalko 23327cf7d04SAleksandr Rybalko /* 234c0e295deSAleksandr Rybalko * Information about if the selection was made bottom-top or 235c0e295deSAleksandr Rybalko * top-bottom is lost due to modulo arithmetics and needs to 236c0e295deSAleksandr Rybalko * be recovered: 23727cf7d04SAleksandr Rybalko */ 238c0e295deSAleksandr Rybalko sz = vb->vb_history_size; 239c0e295deSAleksandr Rybalko tmp = (sz + er - sr) % sz; 240c0e295deSAleksandr Rybalko row = vtbuf_wth(vb, row); 24127cf7d04SAleksandr Rybalko 242c0e295deSAleksandr Rybalko /* Swap start and end if start > end */ 243c0e295deSAleksandr Rybalko if ((2 * tmp) > sz || (tmp == 0 && sc > ec)) { 24427cf7d04SAleksandr Rybalko tmp = sc; sc = ec; ec = tmp; 24527cf7d04SAleksandr Rybalko tmp = sr; sr = er; er = tmp; 24627cf7d04SAleksandr Rybalko } 24727cf7d04SAleksandr Rybalko 248c0e295deSAleksandr Rybalko if (vtbuf_in_this_range(POS_INDEX(sc, sr), POS_INDEX(col, row), 249c0e295deSAleksandr Rybalko POS_INDEX(ec, er), POS_INDEX(0, sz))) 25027cf7d04SAleksandr Rybalko return (1); 251c0e295deSAleksandr Rybalko #endif 25227cf7d04SAleksandr Rybalko 25327cf7d04SAleksandr Rybalko return (0); 25427cf7d04SAleksandr Rybalko } 25527cf7d04SAleksandr Rybalko 256547e74a8SJean-Sébastien Pédron void 257547e74a8SJean-Sébastien Pédron vtbuf_lock(struct vt_buf *vb) 258547e74a8SJean-Sébastien Pédron { 259547e74a8SJean-Sébastien Pédron 260547e74a8SJean-Sébastien Pédron VTBUF_LOCK(vb); 261547e74a8SJean-Sébastien Pédron } 262547e74a8SJean-Sébastien Pédron 263547e74a8SJean-Sébastien Pédron void 264547e74a8SJean-Sébastien Pédron vtbuf_unlock(struct vt_buf *vb) 265547e74a8SJean-Sébastien Pédron { 266547e74a8SJean-Sébastien Pédron 267547e74a8SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 268547e74a8SJean-Sébastien Pédron } 269547e74a8SJean-Sébastien Pédron 270547e74a8SJean-Sébastien Pédron void 271547e74a8SJean-Sébastien Pédron vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 27227cf7d04SAleksandr Rybalko { 27327cf7d04SAleksandr Rybalko 27427cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 27527cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 27627cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 27727cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 27827cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 27927cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 28027cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 28127cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 28200c33067SJean-Sébastien Pédron } 28300c33067SJean-Sébastien Pédron 28427cf7d04SAleksandr Rybalko static inline void 285547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(struct vt_buf *vb, const term_pos_t *p) 28627cf7d04SAleksandr Rybalko { 28727cf7d04SAleksandr Rybalko term_rect_t area; 28827cf7d04SAleksandr Rybalko 28927cf7d04SAleksandr Rybalko area.tr_begin = *p; 29027cf7d04SAleksandr Rybalko area.tr_end.tp_row = p->tp_row + 1; 29127cf7d04SAleksandr Rybalko area.tr_end.tp_col = p->tp_col + 1; 292547e74a8SJean-Sébastien Pédron vtbuf_dirty(vb, &area); 29327cf7d04SAleksandr Rybalko } 29427cf7d04SAleksandr Rybalko 29527cf7d04SAleksandr Rybalko static void 29627cf7d04SAleksandr Rybalko vtbuf_make_undirty(struct vt_buf *vb) 29727cf7d04SAleksandr Rybalko { 29827cf7d04SAleksandr Rybalko 29927cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 30027cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 30127cf7d04SAleksandr Rybalko } 30227cf7d04SAleksandr Rybalko 30327cf7d04SAleksandr Rybalko void 304c3a05e54SJean-Sébastien Pédron vtbuf_undirty(struct vt_buf *vb, term_rect_t *r) 30527cf7d04SAleksandr Rybalko { 30627cf7d04SAleksandr Rybalko 30727cf7d04SAleksandr Rybalko *r = vb->vb_dirtyrect; 30827cf7d04SAleksandr Rybalko vtbuf_make_undirty(vb); 30927cf7d04SAleksandr Rybalko } 31027cf7d04SAleksandr Rybalko 31127cf7d04SAleksandr Rybalko void 31227cf7d04SAleksandr Rybalko vtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 31327cf7d04SAleksandr Rybalko { 31427cf7d04SAleksandr Rybalko const term_pos_t *p1 = &r->tr_begin; 31527cf7d04SAleksandr Rybalko term_rect_t area; 31627cf7d04SAleksandr Rybalko unsigned int rows, cols; 31727cf7d04SAleksandr Rybalko int pr, rdiff; 31827cf7d04SAleksandr Rybalko 31927cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 32027cf7d04SAleksandr Rybalko ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 32127cf7d04SAleksandr Rybalko r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 32227cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 32327cf7d04SAleksandr Rybalko ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 32427cf7d04SAleksandr Rybalko r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 32527cf7d04SAleksandr Rybalko 32627cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 32727cf7d04SAleksandr Rybalko ("vtbuf_copy end.tp_row %d must be less than screen width %d", 32827cf7d04SAleksandr Rybalko r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 32927cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 33027cf7d04SAleksandr Rybalko ("vtbuf_copy end.tp_col %d must be less than screen height %d", 33127cf7d04SAleksandr Rybalko r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 33227cf7d04SAleksandr Rybalko 33327cf7d04SAleksandr Rybalko KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 33427cf7d04SAleksandr Rybalko ("vtbuf_copy tp_row %d must be less than screen width %d", 33527cf7d04SAleksandr Rybalko p2->tp_row, vb->vb_scr_size.tp_row)); 33627cf7d04SAleksandr Rybalko KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 33727cf7d04SAleksandr Rybalko ("vtbuf_copy tp_col %d must be less than screen height %d", 33827cf7d04SAleksandr Rybalko p2->tp_col, vb->vb_scr_size.tp_col)); 33927cf7d04SAleksandr Rybalko 34027cf7d04SAleksandr Rybalko rows = r->tr_end.tp_row - r->tr_begin.tp_row; 34127cf7d04SAleksandr Rybalko rdiff = r->tr_begin.tp_row - p2->tp_row; 34227cf7d04SAleksandr Rybalko cols = r->tr_end.tp_col - r->tr_begin.tp_col; 34327cf7d04SAleksandr Rybalko if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 34427cf7d04SAleksandr Rybalko r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 34527cf7d04SAleksandr Rybalko (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 34613c6f8a0SAleksandr Rybalko rdiff > 0) { /* Only forward direction. Do not eat history. */ 34727cf7d04SAleksandr Rybalko vthistory_addlines(vb, rdiff); 34827cf7d04SAleksandr Rybalko } else if (p2->tp_row < p1->tp_row) { 34927cf7d04SAleksandr Rybalko /* Handle overlapping copies of line segments. */ 35027cf7d04SAleksandr Rybalko /* Move data up. */ 35127cf7d04SAleksandr Rybalko for (pr = 0; pr < rows; pr++) 35227cf7d04SAleksandr Rybalko memmove( 35327cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 35427cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 35527cf7d04SAleksandr Rybalko cols * sizeof(term_char_t)); 35627cf7d04SAleksandr Rybalko } else { 35727cf7d04SAleksandr Rybalko /* Move data down. */ 35827cf7d04SAleksandr Rybalko for (pr = rows - 1; pr >= 0; pr--) 35927cf7d04SAleksandr Rybalko memmove( 36027cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 36127cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 36227cf7d04SAleksandr Rybalko cols * sizeof(term_char_t)); 36327cf7d04SAleksandr Rybalko } 36427cf7d04SAleksandr Rybalko 36527cf7d04SAleksandr Rybalko area.tr_begin = *p2; 36627cf7d04SAleksandr Rybalko area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 36727cf7d04SAleksandr Rybalko area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 36827cf7d04SAleksandr Rybalko vtbuf_dirty(vb, &area); 36927cf7d04SAleksandr Rybalko } 37027cf7d04SAleksandr Rybalko 37127cf7d04SAleksandr Rybalko static void 372547e74a8SJean-Sébastien Pédron vtbuf_do_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 37327cf7d04SAleksandr Rybalko { 37427cf7d04SAleksandr Rybalko unsigned int pr, pc; 37527cf7d04SAleksandr Rybalko term_char_t *row; 37627cf7d04SAleksandr Rybalko 37727cf7d04SAleksandr Rybalko for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 37827cf7d04SAleksandr Rybalko row = vb->vb_rows[(vb->vb_curroffset + pr) % 37927cf7d04SAleksandr Rybalko VTBUF_MAX_HEIGHT(vb)]; 38027cf7d04SAleksandr Rybalko for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 38127cf7d04SAleksandr Rybalko row[pc] = c; 38227cf7d04SAleksandr Rybalko } 38327cf7d04SAleksandr Rybalko } 38427cf7d04SAleksandr Rybalko } 38527cf7d04SAleksandr Rybalko 38627cf7d04SAleksandr Rybalko void 387547e74a8SJean-Sébastien Pédron vtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 38827cf7d04SAleksandr Rybalko { 389547e74a8SJean-Sébastien Pédron 39027cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 391547e74a8SJean-Sébastien Pédron ("vtbuf_fill begin.tp_row %d must be < screen height %d", 39227cf7d04SAleksandr Rybalko r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 39327cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 394547e74a8SJean-Sébastien Pédron ("vtbuf_fill begin.tp_col %d must be < screen width %d", 39527cf7d04SAleksandr Rybalko r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 39627cf7d04SAleksandr Rybalko 39727cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 398547e74a8SJean-Sébastien Pédron ("vtbuf_fill end.tp_row %d must be <= screen height %d", 39927cf7d04SAleksandr Rybalko r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 40027cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 401547e74a8SJean-Sébastien Pédron ("vtbuf_fill end.tp_col %d must be <= screen width %d", 40227cf7d04SAleksandr Rybalko r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 40327cf7d04SAleksandr Rybalko 404547e74a8SJean-Sébastien Pédron vtbuf_do_fill(vb, r, c); 405547e74a8SJean-Sébastien Pédron vtbuf_dirty(vb, r); 40627cf7d04SAleksandr Rybalko } 40727cf7d04SAleksandr Rybalko 40827cf7d04SAleksandr Rybalko static void 40927cf7d04SAleksandr Rybalko vtbuf_init_rows(struct vt_buf *vb) 41027cf7d04SAleksandr Rybalko { 41127cf7d04SAleksandr Rybalko int r; 41227cf7d04SAleksandr Rybalko 41327cf7d04SAleksandr Rybalko vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 41427cf7d04SAleksandr Rybalko 41527cf7d04SAleksandr Rybalko for (r = 0; r < vb->vb_history_size; r++) 4167344ee18SMarius Strobl vb->vb_rows[r] = &vb->vb_buffer[r * vb->vb_scr_size.tp_col]; 41727cf7d04SAleksandr Rybalko } 41827cf7d04SAleksandr Rybalko 419*98f7cf02SJason A. Harmening static void 420*98f7cf02SJason A. Harmening vtbuf_do_clearhistory(struct vt_buf *vb) 42127cf7d04SAleksandr Rybalko { 4227344ee18SMarius Strobl term_rect_t rect; 423df1bc27aSToomas Soome const teken_attr_t *a; 424*98f7cf02SJason A. Harmening term_char_t ch; 42527cf7d04SAleksandr Rybalko 426*98f7cf02SJason A. Harmening a = teken_get_curattr(&vb->vb_terminal->tm_emulator); 427*98f7cf02SJason A. Harmening ch = TCOLOR_FG(a->ta_fgcolor) | TCOLOR_BG(a->ta_bgcolor); 428*98f7cf02SJason A. Harmening 429*98f7cf02SJason A. Harmening rect.tr_begin.tp_row = rect.tr_begin.tp_col = 0; 430*98f7cf02SJason A. Harmening rect.tr_end.tp_col = vb->vb_scr_size.tp_col; 431*98f7cf02SJason A. Harmening rect.tr_end.tp_row = vb->vb_history_size; 432*98f7cf02SJason A. Harmening 433*98f7cf02SJason A. Harmening vtbuf_do_fill(vb, &rect, VTBUF_SPACE_CHAR(ch)); 434*98f7cf02SJason A. Harmening } 435*98f7cf02SJason A. Harmening 436*98f7cf02SJason A. Harmening void 437*98f7cf02SJason A. Harmening vtbuf_init_early(struct vt_buf *vb) 438*98f7cf02SJason A. Harmening { 43927cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_CURSOR; 44027cf7d04SAleksandr Rybalko vb->vb_roffset = 0; 44127cf7d04SAleksandr Rybalko vb->vb_curroffset = 0; 44227cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = 0; 44327cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = 0; 44427cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = 0; 44527cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = 0; 44627cf7d04SAleksandr Rybalko 44727cf7d04SAleksandr Rybalko vtbuf_init_rows(vb); 448*98f7cf02SJason A. Harmening vtbuf_do_clearhistory(vb); 44927cf7d04SAleksandr Rybalko vtbuf_make_undirty(vb); 45027cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 45127cf7d04SAleksandr Rybalko mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 45227cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_MTX_INIT; 45327cf7d04SAleksandr Rybalko } 45427cf7d04SAleksandr Rybalko } 45527cf7d04SAleksandr Rybalko 45627cf7d04SAleksandr Rybalko void 45727cf7d04SAleksandr Rybalko vtbuf_init(struct vt_buf *vb, const term_pos_t *p) 45827cf7d04SAleksandr Rybalko { 45927cf7d04SAleksandr Rybalko int sz; 46027cf7d04SAleksandr Rybalko 46127cf7d04SAleksandr Rybalko vb->vb_scr_size = *p; 46227cf7d04SAleksandr Rybalko vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 46327cf7d04SAleksandr Rybalko 46427cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_STATIC) == 0) { 46527cf7d04SAleksandr Rybalko sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 46627cf7d04SAleksandr Rybalko vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 46727cf7d04SAleksandr Rybalko 46827cf7d04SAleksandr Rybalko sz = vb->vb_history_size * sizeof(term_char_t *); 46927cf7d04SAleksandr Rybalko vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 47027cf7d04SAleksandr Rybalko } 47127cf7d04SAleksandr Rybalko 47227cf7d04SAleksandr Rybalko vtbuf_init_early(vb); 47327cf7d04SAleksandr Rybalko } 47427cf7d04SAleksandr Rybalko 47527cf7d04SAleksandr Rybalko void 476*98f7cf02SJason A. Harmening vtbuf_clearhistory(struct vt_buf *vb) 477*98f7cf02SJason A. Harmening { 478*98f7cf02SJason A. Harmening VTBUF_LOCK(vb); 479*98f7cf02SJason A. Harmening vtbuf_do_clearhistory(vb); 480*98f7cf02SJason A. Harmening VTBUF_UNLOCK(vb); 481*98f7cf02SJason A. Harmening } 482*98f7cf02SJason A. Harmening 483*98f7cf02SJason A. Harmening void 484e1734edfSEd Maste vtbuf_sethistory_size(struct vt_buf *vb, unsigned int size) 48527cf7d04SAleksandr Rybalko { 48627cf7d04SAleksandr Rybalko term_pos_t p; 48727cf7d04SAleksandr Rybalko 48827cf7d04SAleksandr Rybalko /* With same size */ 48927cf7d04SAleksandr Rybalko p.tp_row = vb->vb_scr_size.tp_row; 49027cf7d04SAleksandr Rybalko p.tp_col = vb->vb_scr_size.tp_col; 49127cf7d04SAleksandr Rybalko vtbuf_grow(vb, &p, size); 49227cf7d04SAleksandr Rybalko } 49327cf7d04SAleksandr Rybalko 49427cf7d04SAleksandr Rybalko void 495b7fe4961SJean-Sébastien Pédron vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size) 49627cf7d04SAleksandr Rybalko { 4971454439cSJean-Sébastien Pédron term_char_t *old, *new, **rows, **oldrows, **copyrows, *row, *oldrow; 498e1734edfSEd Maste unsigned int w, h, c, r, old_history_size; 499e1734edfSEd Maste size_t bufsize, rowssize; 500e1734edfSEd Maste int history_full; 501df1bc27aSToomas Soome const teken_attr_t *a; 502df1bc27aSToomas Soome term_char_t ch; 503df1bc27aSToomas Soome 504df1bc27aSToomas Soome a = teken_get_curattr(&vb->vb_terminal->tm_emulator); 505df1bc27aSToomas Soome ch = TCOLOR_FG(a->ta_fgcolor) | TCOLOR_BG(a->ta_bgcolor); 50627cf7d04SAleksandr Rybalko 50727cf7d04SAleksandr Rybalko history_size = MAX(history_size, p->tp_row); 50827cf7d04SAleksandr Rybalko 50927cf7d04SAleksandr Rybalko /* Allocate new buffer. */ 51027cf7d04SAleksandr Rybalko bufsize = history_size * p->tp_col * sizeof(term_char_t); 51127cf7d04SAleksandr Rybalko new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 51227cf7d04SAleksandr Rybalko rowssize = history_size * sizeof(term_pos_t *); 51327cf7d04SAleksandr Rybalko rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 51427cf7d04SAleksandr Rybalko 51527cf7d04SAleksandr Rybalko /* Toggle it. */ 51627cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 51727cf7d04SAleksandr Rybalko old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 51827cf7d04SAleksandr Rybalko oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 51927cf7d04SAleksandr Rybalko copyrows = vb->vb_rows; 5201454439cSJean-Sébastien Pédron 52127cf7d04SAleksandr Rybalko w = vb->vb_scr_size.tp_col; 5221454439cSJean-Sébastien Pédron h = vb->vb_scr_size.tp_row; 5231454439cSJean-Sébastien Pédron old_history_size = vb->vb_history_size; 524e1734edfSEd Maste history_full = vb->vb_flags & VBF_HISTORY_FULL || 525e1734edfSEd Maste vb->vb_curroffset + h >= history_size; 52627cf7d04SAleksandr Rybalko 52727cf7d04SAleksandr Rybalko vb->vb_history_size = history_size; 52827cf7d04SAleksandr Rybalko vb->vb_buffer = new; 52927cf7d04SAleksandr Rybalko vb->vb_rows = rows; 53027cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_STATIC; 53127cf7d04SAleksandr Rybalko vb->vb_scr_size = *p; 53227cf7d04SAleksandr Rybalko vtbuf_init_rows(vb); 53327cf7d04SAleksandr Rybalko 5341454439cSJean-Sébastien Pédron /* 5351454439cSJean-Sébastien Pédron * Copy rows to the new buffer. The first row in the history 5361454439cSJean-Sébastien Pédron * is back to index 0, ie. the new buffer doesn't cycle. 5371454439cSJean-Sébastien Pédron */ 538e1734edfSEd Maste if (history_size > old_history_size) { 5391454439cSJean-Sébastien Pédron for (r = 0; r < old_history_size; r ++) { 5401454439cSJean-Sébastien Pédron row = rows[r]; 5411454439cSJean-Sébastien Pédron 5421454439cSJean-Sébastien Pédron /* Compute the corresponding row in the old buffer. */ 543e1734edfSEd Maste if (history_full) 5441454439cSJean-Sébastien Pédron /* 5451454439cSJean-Sébastien Pédron * The buffer is full, the "top" row is 5461454439cSJean-Sébastien Pédron * the one just after the viewable area 5471454439cSJean-Sébastien Pédron * (curroffset + viewable height) in the 5481454439cSJean-Sébastien Pédron * cycling buffer. The corresponding row 5491454439cSJean-Sébastien Pédron * is computed from this top row. 5501454439cSJean-Sébastien Pédron */ 5511454439cSJean-Sébastien Pédron oldrow = copyrows[ 5521454439cSJean-Sébastien Pédron (vb->vb_curroffset + h + r) % 5531454439cSJean-Sébastien Pédron old_history_size]; 5541454439cSJean-Sébastien Pédron else 5551454439cSJean-Sébastien Pédron /* 5561454439cSJean-Sébastien Pédron * The buffer is not full, therefore, 5571454439cSJean-Sébastien Pédron * we didn't cycle already. The 5581454439cSJean-Sébastien Pédron * corresponding rows are the same in 5591454439cSJean-Sébastien Pédron * both buffers. 5601454439cSJean-Sébastien Pédron */ 5611454439cSJean-Sébastien Pédron oldrow = copyrows[r]; 5621454439cSJean-Sébastien Pédron 5631454439cSJean-Sébastien Pédron memmove(row, oldrow, 5641454439cSJean-Sébastien Pédron MIN(p->tp_col, w) * sizeof(term_char_t)); 5651454439cSJean-Sébastien Pédron 5667344ee18SMarius Strobl /* 5677344ee18SMarius Strobl * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 5687344ee18SMarius Strobl * extended lines of kernel text using the wrong 5697344ee18SMarius Strobl * background color. 5707344ee18SMarius Strobl */ 5711454439cSJean-Sébastien Pédron for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 572df1bc27aSToomas Soome row[c] = VTBUF_SPACE_CHAR(ch); 57327cf7d04SAleksandr Rybalko } 5741454439cSJean-Sébastien Pédron } 5751454439cSJean-Sébastien Pédron 5761454439cSJean-Sébastien Pédron /* Fill remaining rows. */ 577e1734edfSEd Maste for (r = old_history_size; r < history_size; r++) { 578e1734edfSEd Maste row = rows[r]; 579e1734edfSEd Maste for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 580df1bc27aSToomas Soome row[c] = VTBUF_SPACE_CHAR(ch); 581e1734edfSEd Maste } 582e1734edfSEd Maste } 5831454439cSJean-Sébastien Pédron 5841454439cSJean-Sébastien Pédron vb->vb_flags &= ~VBF_HISTORY_FULL; 585e1734edfSEd Maste 586e1734edfSEd Maste /* 587e1734edfSEd Maste * If the screen is already filled (there are non-visible lines 588e1734edfSEd Maste * above the current viewable area), adjust curroffset to the 589e1734edfSEd Maste * new viewable area. 590e1734edfSEd Maste * 591e1734edfSEd Maste * If the old buffer was full, set curroffset to the 592e1734edfSEd Maste * <h>th most recent line of history in the new, non-cycled 593e1734edfSEd Maste * buffer. Otherwise, it didn't cycle, so the old curroffset 594e1734edfSEd Maste * is the same in the new buffer. 595e1734edfSEd Maste */ 596e1734edfSEd Maste if (history_full) 597e1734edfSEd Maste vb->vb_curroffset = old_history_size - h; 5981454439cSJean-Sébastien Pédron } else { 5991454439cSJean-Sébastien Pédron /* 6001454439cSJean-Sébastien Pédron * (old_history_size - history_size) lines of history are 6011454439cSJean-Sébastien Pédron * dropped. 6021454439cSJean-Sébastien Pédron */ 6031454439cSJean-Sébastien Pédron for (r = 0; r < history_size; r ++) { 6041454439cSJean-Sébastien Pédron row = rows[r]; 6051454439cSJean-Sébastien Pédron 6061454439cSJean-Sébastien Pédron /* 6071454439cSJean-Sébastien Pédron * Compute the corresponding row in the old buffer. 6081454439cSJean-Sébastien Pédron * 6091454439cSJean-Sébastien Pédron * See the equivalent if{} block above for an 6101454439cSJean-Sébastien Pédron * explanation. 6111454439cSJean-Sébastien Pédron */ 612e1734edfSEd Maste if (history_full) 6131454439cSJean-Sébastien Pédron oldrow = copyrows[ 6141454439cSJean-Sébastien Pédron (vb->vb_curroffset + h + r + 6151454439cSJean-Sébastien Pédron (old_history_size - history_size)) % 6161454439cSJean-Sébastien Pédron old_history_size]; 6171454439cSJean-Sébastien Pédron else 618e1734edfSEd Maste oldrow = copyrows[r]; 6191454439cSJean-Sébastien Pédron 6201454439cSJean-Sébastien Pédron memmove(row, oldrow, 6211454439cSJean-Sébastien Pédron MIN(p->tp_col, w) * sizeof(term_char_t)); 6221454439cSJean-Sébastien Pédron 6231454439cSJean-Sébastien Pédron /* 6241454439cSJean-Sébastien Pédron * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 6251454439cSJean-Sébastien Pédron * extended lines of kernel text using the wrong 6261454439cSJean-Sébastien Pédron * background color. 6271454439cSJean-Sébastien Pédron */ 6281454439cSJean-Sébastien Pédron for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 629df1bc27aSToomas Soome row[c] = VTBUF_SPACE_CHAR(ch); 63027cf7d04SAleksandr Rybalko } 63127cf7d04SAleksandr Rybalko } 6321454439cSJean-Sébastien Pédron 633e1734edfSEd Maste if (history_full) { 634e1734edfSEd Maste vb->vb_curroffset = history_size - h; 6351454439cSJean-Sébastien Pédron vb->vb_flags |= VBF_HISTORY_FULL; 6361454439cSJean-Sébastien Pédron } 6371454439cSJean-Sébastien Pédron } 6381454439cSJean-Sébastien Pédron 639e1734edfSEd Maste vb->vb_roffset = vb->vb_curroffset; 640e1734edfSEd Maste 641da49f6bcSJean-Sébastien Pédron /* Adjust cursor position. */ 642da49f6bcSJean-Sébastien Pédron if (vb->vb_cursor.tp_col > p->tp_col - 1) 643da49f6bcSJean-Sébastien Pédron /* 644da49f6bcSJean-Sébastien Pédron * Move cursor to the last column, in case its previous 645da49f6bcSJean-Sébastien Pédron * position is outside of the new screen area. 646da49f6bcSJean-Sébastien Pédron */ 647da49f6bcSJean-Sébastien Pédron vb->vb_cursor.tp_col = p->tp_col - 1; 648da49f6bcSJean-Sébastien Pédron 649da49f6bcSJean-Sébastien Pédron if (vb->vb_curroffset > 0 || vb->vb_cursor.tp_row > p->tp_row - 1) 650da49f6bcSJean-Sébastien Pédron /* Move cursor to the last line on the screen. */ 651da49f6bcSJean-Sébastien Pédron vb->vb_cursor.tp_row = p->tp_row - 1; 652da49f6bcSJean-Sébastien Pédron 65327cf7d04SAleksandr Rybalko VTBUF_UNLOCK(vb); 6541454439cSJean-Sébastien Pédron 65527cf7d04SAleksandr Rybalko /* Deallocate old buffer. */ 65627cf7d04SAleksandr Rybalko free(old, M_VTBUF); 65727cf7d04SAleksandr Rybalko free(oldrows, M_VTBUF); 65827cf7d04SAleksandr Rybalko } 65927cf7d04SAleksandr Rybalko 66027cf7d04SAleksandr Rybalko void 66127cf7d04SAleksandr Rybalko vtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 66227cf7d04SAleksandr Rybalko { 66327cf7d04SAleksandr Rybalko term_char_t *row; 66427cf7d04SAleksandr Rybalko 66527cf7d04SAleksandr Rybalko KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 66627cf7d04SAleksandr Rybalko ("vtbuf_putchar tp_row %d must be less than screen width %d", 66727cf7d04SAleksandr Rybalko p->tp_row, vb->vb_scr_size.tp_row)); 66827cf7d04SAleksandr Rybalko KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 66927cf7d04SAleksandr Rybalko ("vtbuf_putchar tp_col %d must be less than screen height %d", 67027cf7d04SAleksandr Rybalko p->tp_col, vb->vb_scr_size.tp_col)); 67127cf7d04SAleksandr Rybalko 67227cf7d04SAleksandr Rybalko row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 67327cf7d04SAleksandr Rybalko VTBUF_MAX_HEIGHT(vb)]; 67427cf7d04SAleksandr Rybalko if (row[p->tp_col] != c) { 67527cf7d04SAleksandr Rybalko row[p->tp_col] = c; 676547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, p); 67727cf7d04SAleksandr Rybalko } 67827cf7d04SAleksandr Rybalko } 67927cf7d04SAleksandr Rybalko 68027cf7d04SAleksandr Rybalko void 68127cf7d04SAleksandr Rybalko vtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 68227cf7d04SAleksandr Rybalko { 68327cf7d04SAleksandr Rybalko if (vb->vb_flags & VBF_CURSOR) { 684547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 68527cf7d04SAleksandr Rybalko vb->vb_cursor = *p; 686547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 68727cf7d04SAleksandr Rybalko } else { 68827cf7d04SAleksandr Rybalko vb->vb_cursor = *p; 68927cf7d04SAleksandr Rybalko } 69027cf7d04SAleksandr Rybalko } 69127cf7d04SAleksandr Rybalko 6920f49db6eSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 69327cf7d04SAleksandr Rybalko static void 69427cf7d04SAleksandr Rybalko vtbuf_flush_mark(struct vt_buf *vb) 69527cf7d04SAleksandr Rybalko { 69627cf7d04SAleksandr Rybalko term_rect_t area; 69727cf7d04SAleksandr Rybalko int s, e; 69827cf7d04SAleksandr Rybalko 69927cf7d04SAleksandr Rybalko /* Notify renderer to update marked region. */ 700c0e295deSAleksandr Rybalko if ((vb->vb_mark_start.tp_col != vb->vb_mark_end.tp_col) || 701c0e295deSAleksandr Rybalko (vb->vb_mark_start.tp_row != vb->vb_mark_end.tp_row)) { 70227cf7d04SAleksandr Rybalko 70327cf7d04SAleksandr Rybalko s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 70427cf7d04SAleksandr Rybalko e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 70527cf7d04SAleksandr Rybalko 70627cf7d04SAleksandr Rybalko area.tr_begin.tp_col = 0; 70727cf7d04SAleksandr Rybalko area.tr_begin.tp_row = MIN(s, e); 70827cf7d04SAleksandr Rybalko 70927cf7d04SAleksandr Rybalko area.tr_end.tp_col = vb->vb_scr_size.tp_col; 71027cf7d04SAleksandr Rybalko area.tr_end.tp_row = MAX(s, e) + 1; 71127cf7d04SAleksandr Rybalko 712547e74a8SJean-Sébastien Pédron VTBUF_LOCK(vb); 71327cf7d04SAleksandr Rybalko vtbuf_dirty(vb, &area); 714547e74a8SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 71527cf7d04SAleksandr Rybalko } 71627cf7d04SAleksandr Rybalko } 71727cf7d04SAleksandr Rybalko 71827cf7d04SAleksandr Rybalko int 71927cf7d04SAleksandr Rybalko vtbuf_get_marked_len(struct vt_buf *vb) 72027cf7d04SAleksandr Rybalko { 72127cf7d04SAleksandr Rybalko int ei, si, sz; 72227cf7d04SAleksandr Rybalko term_pos_t s, e; 72327cf7d04SAleksandr Rybalko 72427cf7d04SAleksandr Rybalko /* Swap according to window coordinates. */ 72527cf7d04SAleksandr Rybalko if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 72627cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col) > 72727cf7d04SAleksandr Rybalko POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 72827cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col)) { 72927cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_start); 73027cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_end); 73127cf7d04SAleksandr Rybalko } else { 73227cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_start); 73327cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_end); 73427cf7d04SAleksandr Rybalko } 73527cf7d04SAleksandr Rybalko 73627cf7d04SAleksandr Rybalko si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 73727cf7d04SAleksandr Rybalko ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 73827cf7d04SAleksandr Rybalko 73927cf7d04SAleksandr Rybalko /* Number symbols and number of rows to inject \n */ 74044f751a2SAleksandr Rybalko sz = ei - si + ((e.tp_row - s.tp_row) * 2); 74127cf7d04SAleksandr Rybalko 74227cf7d04SAleksandr Rybalko return (sz * sizeof(term_char_t)); 74327cf7d04SAleksandr Rybalko } 74427cf7d04SAleksandr Rybalko 74527cf7d04SAleksandr Rybalko void 74627cf7d04SAleksandr Rybalko vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 74727cf7d04SAleksandr Rybalko { 74827cf7d04SAleksandr Rybalko int i, r, c, cs, ce; 74927cf7d04SAleksandr Rybalko term_pos_t s, e; 75027cf7d04SAleksandr Rybalko 75127cf7d04SAleksandr Rybalko /* Swap according to window coordinates. */ 75227cf7d04SAleksandr Rybalko if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 75327cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col) > 75427cf7d04SAleksandr Rybalko POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 75527cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col)) { 75627cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_start); 75727cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_end); 75827cf7d04SAleksandr Rybalko } else { 75927cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_start); 76027cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_end); 76127cf7d04SAleksandr Rybalko } 76227cf7d04SAleksandr Rybalko 76327cf7d04SAleksandr Rybalko i = 0; 76427cf7d04SAleksandr Rybalko for (r = s.tp_row; r <= e.tp_row; r ++) { 76527cf7d04SAleksandr Rybalko cs = (r == s.tp_row)?s.tp_col:0; 76627cf7d04SAleksandr Rybalko ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 76727cf7d04SAleksandr Rybalko for (c = cs; c < ce; c ++) { 76827cf7d04SAleksandr Rybalko buf[i++] = vb->vb_rows[r][c]; 76927cf7d04SAleksandr Rybalko } 77027cf7d04SAleksandr Rybalko /* Add new line for all rows, but not for last one. */ 77127cf7d04SAleksandr Rybalko if (r != e.tp_row) { 77227cf7d04SAleksandr Rybalko buf[i++] = '\r'; 77327cf7d04SAleksandr Rybalko buf[i++] = '\n'; 77427cf7d04SAleksandr Rybalko } 77527cf7d04SAleksandr Rybalko } 77627cf7d04SAleksandr Rybalko } 77727cf7d04SAleksandr Rybalko 77827cf7d04SAleksandr Rybalko int 77927cf7d04SAleksandr Rybalko vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 78027cf7d04SAleksandr Rybalko { 78127cf7d04SAleksandr Rybalko term_char_t *r; 78227cf7d04SAleksandr Rybalko int i; 78327cf7d04SAleksandr Rybalko 78427cf7d04SAleksandr Rybalko switch (type) { 78527cf7d04SAleksandr Rybalko case VTB_MARK_END: /* B1 UP */ 78627cf7d04SAleksandr Rybalko if (vb->vb_mark_last != VTB_MARK_MOVE) 78727cf7d04SAleksandr Rybalko return (0); 78827cf7d04SAleksandr Rybalko /* FALLTHROUGH */ 78927cf7d04SAleksandr Rybalko case VTB_MARK_MOVE: 79027cf7d04SAleksandr Rybalko case VTB_MARK_EXTEND: 79127cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 79227cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = col; 79327cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 79427cf7d04SAleksandr Rybalko break; 79527cf7d04SAleksandr Rybalko case VTB_MARK_START: 79627cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 79727cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = col; 79827cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 79927cf7d04SAleksandr Rybalko /* Start again, so clear end point. */ 80027cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = col; 80127cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 80227cf7d04SAleksandr Rybalko break; 80327cf7d04SAleksandr Rybalko case VTB_MARK_WORD: 80427cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 80527cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 80627cf7d04SAleksandr Rybalko vtbuf_wth(vb, row); 80727cf7d04SAleksandr Rybalko r = vb->vb_rows[vb->vb_mark_start.tp_row]; 80827cf7d04SAleksandr Rybalko for (i = col; i >= 0; i --) { 80927cf7d04SAleksandr Rybalko if (TCHAR_CHARACTER(r[i]) == ' ') { 81027cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = i + 1; 81127cf7d04SAleksandr Rybalko break; 81227cf7d04SAleksandr Rybalko } 81327cf7d04SAleksandr Rybalko } 81427cf7d04SAleksandr Rybalko for (i = col; i < vb->vb_scr_size.tp_col; i ++) { 81527cf7d04SAleksandr Rybalko if (TCHAR_CHARACTER(r[i]) == ' ') { 81627cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = i; 81727cf7d04SAleksandr Rybalko break; 81827cf7d04SAleksandr Rybalko } 81927cf7d04SAleksandr Rybalko } 82027cf7d04SAleksandr Rybalko if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col) 82127cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 82227cf7d04SAleksandr Rybalko break; 82327cf7d04SAleksandr Rybalko case VTB_MARK_ROW: 82427cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 82527cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = 0; 82627cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 82727cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 82827cf7d04SAleksandr Rybalko vtbuf_wth(vb, row); 82927cf7d04SAleksandr Rybalko break; 83027cf7d04SAleksandr Rybalko case VTB_MARK_NONE: 83127cf7d04SAleksandr Rybalko vb->vb_mark_last = type; 83227cf7d04SAleksandr Rybalko /* FALLTHROUGH */ 83327cf7d04SAleksandr Rybalko default: 83427cf7d04SAleksandr Rybalko /* panic? */ 83527cf7d04SAleksandr Rybalko return (0); 83627cf7d04SAleksandr Rybalko } 83727cf7d04SAleksandr Rybalko 83827cf7d04SAleksandr Rybalko vb->vb_mark_last = type; 83927cf7d04SAleksandr Rybalko /* Draw new marked region. */ 84027cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); 84127cf7d04SAleksandr Rybalko return (1); 84227cf7d04SAleksandr Rybalko } 8430f49db6eSAleksandr Rybalko #endif 84427cf7d04SAleksandr Rybalko 84527cf7d04SAleksandr Rybalko void 84627cf7d04SAleksandr Rybalko vtbuf_cursor_visibility(struct vt_buf *vb, int yes) 84727cf7d04SAleksandr Rybalko { 84827cf7d04SAleksandr Rybalko int oflags, nflags; 84927cf7d04SAleksandr Rybalko 85027cf7d04SAleksandr Rybalko oflags = vb->vb_flags; 85127cf7d04SAleksandr Rybalko if (yes) 85227cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_CURSOR; 85327cf7d04SAleksandr Rybalko else 85427cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_CURSOR; 85527cf7d04SAleksandr Rybalko nflags = vb->vb_flags; 85627cf7d04SAleksandr Rybalko 85727cf7d04SAleksandr Rybalko if (oflags != nflags) 858547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 85927cf7d04SAleksandr Rybalko } 86027cf7d04SAleksandr Rybalko 86127cf7d04SAleksandr Rybalko void 86227cf7d04SAleksandr Rybalko vtbuf_scroll_mode(struct vt_buf *vb, int yes) 86327cf7d04SAleksandr Rybalko { 86427cf7d04SAleksandr Rybalko int oflags, nflags; 86527cf7d04SAleksandr Rybalko 86627cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 86727cf7d04SAleksandr Rybalko oflags = vb->vb_flags; 86827cf7d04SAleksandr Rybalko if (yes) 86927cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_SCROLL; 87027cf7d04SAleksandr Rybalko else 87127cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_SCROLL; 87227cf7d04SAleksandr Rybalko nflags = vb->vb_flags; 87327cf7d04SAleksandr Rybalko 87427cf7d04SAleksandr Rybalko if (oflags != nflags) 875547e74a8SJean-Sébastien Pédron vtbuf_dirty_cell(vb, &vb->vb_cursor); 87600c33067SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 87727cf7d04SAleksandr Rybalko } 878