127cf7d04SAleksandr Rybalko /*- 227cf7d04SAleksandr Rybalko * Copyright (c) 2009, 2013 The FreeBSD Foundation 327cf7d04SAleksandr Rybalko * All rights reserved. 427cf7d04SAleksandr Rybalko * 527cf7d04SAleksandr Rybalko * This software was developed by Ed Schouten under sponsorship from the 627cf7d04SAleksandr Rybalko * FreeBSD Foundation. 727cf7d04SAleksandr Rybalko * 827cf7d04SAleksandr Rybalko * Portions of this software were developed by Oleksandr Rybalko 927cf7d04SAleksandr Rybalko * under sponsorship from the FreeBSD Foundation. 1027cf7d04SAleksandr Rybalko * 1127cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 1227cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 1327cf7d04SAleksandr Rybalko * are met: 1427cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1527cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1627cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1727cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 1827cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 1927cf7d04SAleksandr Rybalko * 2027cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2127cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2227cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2327cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2427cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2527cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2627cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2727cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2827cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2927cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3027cf7d04SAleksandr Rybalko * SUCH DAMAGE. 3127cf7d04SAleksandr Rybalko */ 3227cf7d04SAleksandr Rybalko 3327cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 3427cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 3527cf7d04SAleksandr Rybalko 3627cf7d04SAleksandr Rybalko #include <sys/param.h> 3727cf7d04SAleksandr Rybalko #include <sys/kernel.h> 3827cf7d04SAleksandr Rybalko #include <sys/lock.h> 3927cf7d04SAleksandr Rybalko #include <sys/malloc.h> 4027cf7d04SAleksandr Rybalko #include <sys/mutex.h> 417344ee18SMarius Strobl #include <sys/reboot.h> 4227cf7d04SAleksandr Rybalko #include <sys/systm.h> 4327cf7d04SAleksandr Rybalko 4427cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 4527cf7d04SAleksandr Rybalko 4627cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); 4727cf7d04SAleksandr Rybalko 4827cf7d04SAleksandr Rybalko #define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) 4927cf7d04SAleksandr Rybalko #define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) 5027cf7d04SAleksandr Rybalko 5127cf7d04SAleksandr Rybalko #define POS_INDEX(c, r) (((r) << 12) + (c)) 5227cf7d04SAleksandr Rybalko #define POS_COPY(d, s) do { \ 5327cf7d04SAleksandr Rybalko (d).tp_col = (s).tp_col; \ 5427cf7d04SAleksandr Rybalko (d).tp_row = (s).tp_row; \ 5527cf7d04SAleksandr Rybalko } while (0) 5627cf7d04SAleksandr Rybalko 5727cf7d04SAleksandr Rybalko 5827cf7d04SAleksandr Rybalko /* 5927cf7d04SAleksandr Rybalko * line4 6027cf7d04SAleksandr Rybalko * line5 <--- curroffset (terminal output to that line) 6127cf7d04SAleksandr Rybalko * line0 6227cf7d04SAleksandr Rybalko * line1 <--- roffset (history display from that point) 6327cf7d04SAleksandr Rybalko * line2 6427cf7d04SAleksandr Rybalko * line3 6527cf7d04SAleksandr Rybalko */ 6627cf7d04SAleksandr Rybalko int 6727cf7d04SAleksandr Rybalko vthistory_seek(struct vt_buf *vb, int offset, int whence) 6827cf7d04SAleksandr Rybalko { 6927cf7d04SAleksandr Rybalko int diff, top, bottom, roffset; 7027cf7d04SAleksandr Rybalko 7127cf7d04SAleksandr Rybalko /* No scrolling if not enabled. */ 7227cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_SCROLL) == 0) { 7327cf7d04SAleksandr Rybalko if (vb->vb_roffset != vb->vb_curroffset) { 7427cf7d04SAleksandr Rybalko vb->vb_roffset = vb->vb_curroffset; 7527cf7d04SAleksandr Rybalko return (0xffff); 7627cf7d04SAleksandr Rybalko } 7727cf7d04SAleksandr Rybalko return (0); /* No changes */ 7827cf7d04SAleksandr Rybalko } 7927cf7d04SAleksandr Rybalko 80*1454439cSJean-Sébastien Pédron /* "top" may be a negative integer. */ 81*1454439cSJean-Sébastien Pédron bottom = vb->vb_curroffset; 82*1454439cSJean-Sébastien Pédron top = (vb->vb_flags & VBF_HISTORY_FULL) ? 83*1454439cSJean-Sébastien Pédron bottom + vb->vb_scr_size.tp_row - vb->vb_history_size : 84*1454439cSJean-Sébastien Pédron 0; 85*1454439cSJean-Sébastien Pédron 8627cf7d04SAleksandr Rybalko switch (whence) { 8727cf7d04SAleksandr Rybalko case VHS_SET: 88*1454439cSJean-Sébastien Pédron if (offset < 0) 89*1454439cSJean-Sébastien Pédron offset = 0; 90*1454439cSJean-Sébastien Pédron roffset = top + offset; 9127cf7d04SAleksandr Rybalko break; 9227cf7d04SAleksandr Rybalko case VHS_CUR: 93*1454439cSJean-Sébastien Pédron /* 94*1454439cSJean-Sébastien Pédron * Operate on copy of offset value, since it temporary 95*1454439cSJean-Sébastien Pédron * can be bigger than amount of rows in buffer. 96*1454439cSJean-Sébastien Pédron */ 97*1454439cSJean-Sébastien Pédron roffset = vb->vb_roffset; 98*1454439cSJean-Sébastien Pédron if (roffset >= bottom + vb->vb_scr_size.tp_row) 99*1454439cSJean-Sébastien Pédron roffset -= vb->vb_history_size; 100*1454439cSJean-Sébastien Pédron 10127cf7d04SAleksandr Rybalko roffset += offset; 102*1454439cSJean-Sébastien Pédron roffset = MAX(roffset, top); 103*1454439cSJean-Sébastien Pédron roffset = MIN(roffset, bottom); 104*1454439cSJean-Sébastien Pédron 105*1454439cSJean-Sébastien Pédron if (roffset < 0) 106*1454439cSJean-Sébastien Pédron roffset = vb->vb_history_size + roffset; 107*1454439cSJean-Sébastien Pédron 10827cf7d04SAleksandr Rybalko break; 10927cf7d04SAleksandr Rybalko case VHS_END: 11027cf7d04SAleksandr Rybalko /* Go to current offset. */ 111*1454439cSJean-Sébastien Pédron roffset = vb->vb_curroffset; 11227cf7d04SAleksandr Rybalko break; 11327cf7d04SAleksandr Rybalko } 11427cf7d04SAleksandr Rybalko 115*1454439cSJean-Sébastien Pédron diff = vb->vb_roffset != roffset; 11627cf7d04SAleksandr Rybalko vb->vb_roffset = roffset; 117*1454439cSJean-Sébastien Pédron 11827cf7d04SAleksandr Rybalko return (diff); 11927cf7d04SAleksandr Rybalko } 12027cf7d04SAleksandr Rybalko 12127cf7d04SAleksandr Rybalko void 12227cf7d04SAleksandr Rybalko vthistory_addlines(struct vt_buf *vb, int offset) 12327cf7d04SAleksandr Rybalko { 12427cf7d04SAleksandr Rybalko 12527cf7d04SAleksandr Rybalko vb->vb_curroffset += offset; 12627cf7d04SAleksandr Rybalko if (vb->vb_curroffset < 0) 12727cf7d04SAleksandr Rybalko vb->vb_curroffset = 0; 128*1454439cSJean-Sébastien Pédron if (vb->vb_curroffset + vb->vb_scr_size.tp_row >= vb->vb_history_size) 129*1454439cSJean-Sébastien Pédron vb->vb_flags |= VBF_HISTORY_FULL; 13027cf7d04SAleksandr Rybalko vb->vb_curroffset %= vb->vb_history_size; 13127cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_SCROLL) == 0) { 13227cf7d04SAleksandr Rybalko vb->vb_roffset = vb->vb_curroffset; 13327cf7d04SAleksandr Rybalko } 13427cf7d04SAleksandr Rybalko } 13527cf7d04SAleksandr Rybalko 13627cf7d04SAleksandr Rybalko void 13727cf7d04SAleksandr Rybalko vthistory_getpos(const struct vt_buf *vb, unsigned int *offset) 13827cf7d04SAleksandr Rybalko { 13927cf7d04SAleksandr Rybalko 14027cf7d04SAleksandr Rybalko *offset = vb->vb_roffset; 14127cf7d04SAleksandr Rybalko } 14227cf7d04SAleksandr Rybalko 1430f49db6eSAleksandr Rybalko #ifndef SC_NO_CUTPASTE /* Only mouse support use it now. */ 14427cf7d04SAleksandr Rybalko /* Translate current view row number to history row. */ 14527cf7d04SAleksandr Rybalko static int 14627cf7d04SAleksandr Rybalko vtbuf_wth(struct vt_buf *vb, int row) 14727cf7d04SAleksandr Rybalko { 14827cf7d04SAleksandr Rybalko 14927cf7d04SAleksandr Rybalko return ((vb->vb_roffset + row) % vb->vb_history_size); 15027cf7d04SAleksandr Rybalko } 1510f49db6eSAleksandr Rybalko #endif 15227cf7d04SAleksandr Rybalko 15327cf7d04SAleksandr Rybalko /* Translate history row to current view row number. */ 15427cf7d04SAleksandr Rybalko static int 155c6e1a987SJean-Sébastien Pédron vtbuf_htw(const struct vt_buf *vb, int row) 15627cf7d04SAleksandr Rybalko { 15727cf7d04SAleksandr Rybalko 15827cf7d04SAleksandr Rybalko /* 15927cf7d04SAleksandr Rybalko * total 1000 rows. 16027cf7d04SAleksandr Rybalko * History offset roffset winrow 16127cf7d04SAleksandr Rybalko * 205 200 ((205 - 200 + 1000) % 1000) = 5 16227cf7d04SAleksandr Rybalko * 90 990 ((90 - 990 + 1000) % 1000) = 100 16327cf7d04SAleksandr Rybalko */ 16427cf7d04SAleksandr Rybalko return ((row - vb->vb_roffset + vb->vb_history_size) % 16527cf7d04SAleksandr Rybalko vb->vb_history_size); 16627cf7d04SAleksandr Rybalko } 16727cf7d04SAleksandr Rybalko 16827cf7d04SAleksandr Rybalko int 169c6e1a987SJean-Sébastien Pédron vtbuf_iscursor(const struct vt_buf *vb, int row, int col) 17027cf7d04SAleksandr Rybalko { 17127cf7d04SAleksandr Rybalko int sc, sr, ec, er, tmp; 17227cf7d04SAleksandr Rybalko 17327cf7d04SAleksandr Rybalko if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 17427cf7d04SAleksandr Rybalko (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 17527cf7d04SAleksandr Rybalko return (1); 17627cf7d04SAleksandr Rybalko 17727cf7d04SAleksandr Rybalko /* Mark cut/paste region. */ 17827cf7d04SAleksandr Rybalko 17927cf7d04SAleksandr Rybalko /* 18027cf7d04SAleksandr Rybalko * Luckily screen view is not like circular buffer, so we will 18127cf7d04SAleksandr Rybalko * calculate in screen coordinates. Translate first. 18227cf7d04SAleksandr Rybalko */ 18327cf7d04SAleksandr Rybalko sc = vb->vb_mark_start.tp_col; 18427cf7d04SAleksandr Rybalko sr = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 18527cf7d04SAleksandr Rybalko ec = vb->vb_mark_end.tp_col; 18627cf7d04SAleksandr Rybalko er = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 18727cf7d04SAleksandr Rybalko 18827cf7d04SAleksandr Rybalko 18927cf7d04SAleksandr Rybalko /* Swap start and end if start > end. */ 19027cf7d04SAleksandr Rybalko if (POS_INDEX(sc, sr) > POS_INDEX(ec, er)) { 19127cf7d04SAleksandr Rybalko tmp = sc; sc = ec; ec = tmp; 19227cf7d04SAleksandr Rybalko tmp = sr; sr = er; er = tmp; 19327cf7d04SAleksandr Rybalko } 19427cf7d04SAleksandr Rybalko 19527cf7d04SAleksandr Rybalko if ((POS_INDEX(sc, sr) <= POS_INDEX(col, row)) && 19627cf7d04SAleksandr Rybalko (POS_INDEX(col, row) < POS_INDEX(ec, er))) 19727cf7d04SAleksandr Rybalko return (1); 19827cf7d04SAleksandr Rybalko 19927cf7d04SAleksandr Rybalko return (0); 20027cf7d04SAleksandr Rybalko } 20127cf7d04SAleksandr Rybalko 20227cf7d04SAleksandr Rybalko static inline void 20300c33067SJean-Sébastien Pédron vtbuf_dirty_locked(struct vt_buf *vb, const term_rect_t *area) 20427cf7d04SAleksandr Rybalko { 20527cf7d04SAleksandr Rybalko 20627cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 20727cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 20827cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 20927cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 21027cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 21127cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 21227cf7d04SAleksandr Rybalko if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 21327cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 21400c33067SJean-Sébastien Pédron } 21500c33067SJean-Sébastien Pédron 21682276bbbSJean-Sébastien Pédron void 21700c33067SJean-Sébastien Pédron vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 21800c33067SJean-Sébastien Pédron { 21900c33067SJean-Sébastien Pédron 22000c33067SJean-Sébastien Pédron VTBUF_LOCK(vb); 22100c33067SJean-Sébastien Pédron vtbuf_dirty_locked(vb, area); 22227cf7d04SAleksandr Rybalko VTBUF_UNLOCK(vb); 22327cf7d04SAleksandr Rybalko } 22427cf7d04SAleksandr Rybalko 22527cf7d04SAleksandr Rybalko static inline void 22600c33067SJean-Sébastien Pédron vtbuf_dirty_cell_locked(struct vt_buf *vb, const term_pos_t *p) 22727cf7d04SAleksandr Rybalko { 22827cf7d04SAleksandr Rybalko term_rect_t area; 22927cf7d04SAleksandr Rybalko 23027cf7d04SAleksandr Rybalko area.tr_begin = *p; 23127cf7d04SAleksandr Rybalko area.tr_end.tp_row = p->tp_row + 1; 23227cf7d04SAleksandr Rybalko area.tr_end.tp_col = p->tp_col + 1; 23300c33067SJean-Sébastien Pédron vtbuf_dirty_locked(vb, &area); 23427cf7d04SAleksandr Rybalko } 23527cf7d04SAleksandr Rybalko 23627cf7d04SAleksandr Rybalko static void 23727cf7d04SAleksandr Rybalko vtbuf_make_undirty(struct vt_buf *vb) 23827cf7d04SAleksandr Rybalko { 23927cf7d04SAleksandr Rybalko 24027cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 24127cf7d04SAleksandr Rybalko vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 24227cf7d04SAleksandr Rybalko } 24327cf7d04SAleksandr Rybalko 24427cf7d04SAleksandr Rybalko void 245c3a05e54SJean-Sébastien Pédron vtbuf_undirty(struct vt_buf *vb, term_rect_t *r) 24627cf7d04SAleksandr Rybalko { 24727cf7d04SAleksandr Rybalko 24827cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 24927cf7d04SAleksandr Rybalko *r = vb->vb_dirtyrect; 25027cf7d04SAleksandr Rybalko vtbuf_make_undirty(vb); 25127cf7d04SAleksandr Rybalko VTBUF_UNLOCK(vb); 25227cf7d04SAleksandr Rybalko } 25327cf7d04SAleksandr Rybalko 25427cf7d04SAleksandr Rybalko void 25527cf7d04SAleksandr Rybalko vtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 25627cf7d04SAleksandr Rybalko { 25727cf7d04SAleksandr Rybalko const term_pos_t *p1 = &r->tr_begin; 25827cf7d04SAleksandr Rybalko term_rect_t area; 25927cf7d04SAleksandr Rybalko unsigned int rows, cols; 26027cf7d04SAleksandr Rybalko int pr, rdiff; 26127cf7d04SAleksandr Rybalko 26227cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 26327cf7d04SAleksandr Rybalko ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 26427cf7d04SAleksandr Rybalko r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 26527cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 26627cf7d04SAleksandr Rybalko ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 26727cf7d04SAleksandr Rybalko r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 26827cf7d04SAleksandr Rybalko 26927cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 27027cf7d04SAleksandr Rybalko ("vtbuf_copy end.tp_row %d must be less than screen width %d", 27127cf7d04SAleksandr Rybalko r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 27227cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 27327cf7d04SAleksandr Rybalko ("vtbuf_copy end.tp_col %d must be less than screen height %d", 27427cf7d04SAleksandr Rybalko r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 27527cf7d04SAleksandr Rybalko 27627cf7d04SAleksandr Rybalko KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 27727cf7d04SAleksandr Rybalko ("vtbuf_copy tp_row %d must be less than screen width %d", 27827cf7d04SAleksandr Rybalko p2->tp_row, vb->vb_scr_size.tp_row)); 27927cf7d04SAleksandr Rybalko KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 28027cf7d04SAleksandr Rybalko ("vtbuf_copy tp_col %d must be less than screen height %d", 28127cf7d04SAleksandr Rybalko p2->tp_col, vb->vb_scr_size.tp_col)); 28227cf7d04SAleksandr Rybalko 28327cf7d04SAleksandr Rybalko rows = r->tr_end.tp_row - r->tr_begin.tp_row; 28427cf7d04SAleksandr Rybalko rdiff = r->tr_begin.tp_row - p2->tp_row; 28527cf7d04SAleksandr Rybalko cols = r->tr_end.tp_col - r->tr_begin.tp_col; 28627cf7d04SAleksandr Rybalko if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 28727cf7d04SAleksandr Rybalko r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 28827cf7d04SAleksandr Rybalko (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 28913c6f8a0SAleksandr Rybalko rdiff > 0) { /* Only forward direction. Do not eat history. */ 29027cf7d04SAleksandr Rybalko vthistory_addlines(vb, rdiff); 29127cf7d04SAleksandr Rybalko } else if (p2->tp_row < p1->tp_row) { 29227cf7d04SAleksandr Rybalko /* Handle overlapping copies of line segments. */ 29327cf7d04SAleksandr Rybalko /* Move data up. */ 29427cf7d04SAleksandr Rybalko for (pr = 0; pr < rows; pr++) 29527cf7d04SAleksandr Rybalko memmove( 29627cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 29727cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 29827cf7d04SAleksandr Rybalko cols * sizeof(term_char_t)); 29927cf7d04SAleksandr Rybalko } else { 30027cf7d04SAleksandr Rybalko /* Move data down. */ 30127cf7d04SAleksandr Rybalko for (pr = rows - 1; pr >= 0; pr--) 30227cf7d04SAleksandr Rybalko memmove( 30327cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 30427cf7d04SAleksandr Rybalko &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 30527cf7d04SAleksandr Rybalko cols * sizeof(term_char_t)); 30627cf7d04SAleksandr Rybalko } 30727cf7d04SAleksandr Rybalko 30827cf7d04SAleksandr Rybalko area.tr_begin = *p2; 30927cf7d04SAleksandr Rybalko area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 31027cf7d04SAleksandr Rybalko area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 31127cf7d04SAleksandr Rybalko vtbuf_dirty(vb, &area); 31227cf7d04SAleksandr Rybalko } 31327cf7d04SAleksandr Rybalko 31427cf7d04SAleksandr Rybalko static void 31527cf7d04SAleksandr Rybalko vtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 31627cf7d04SAleksandr Rybalko { 31727cf7d04SAleksandr Rybalko unsigned int pr, pc; 31827cf7d04SAleksandr Rybalko term_char_t *row; 31927cf7d04SAleksandr Rybalko 32027cf7d04SAleksandr Rybalko for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 32127cf7d04SAleksandr Rybalko row = vb->vb_rows[(vb->vb_curroffset + pr) % 32227cf7d04SAleksandr Rybalko VTBUF_MAX_HEIGHT(vb)]; 32327cf7d04SAleksandr Rybalko for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 32427cf7d04SAleksandr Rybalko row[pc] = c; 32527cf7d04SAleksandr Rybalko } 32627cf7d04SAleksandr Rybalko } 32727cf7d04SAleksandr Rybalko } 32827cf7d04SAleksandr Rybalko 32927cf7d04SAleksandr Rybalko void 33027cf7d04SAleksandr Rybalko vtbuf_fill_locked(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 33127cf7d04SAleksandr Rybalko { 33227cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 333ba23b435SEd Maste ("vtbuf_fill_locked begin.tp_row %d must be < screen height %d", 33427cf7d04SAleksandr Rybalko r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 33527cf7d04SAleksandr Rybalko KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 336ba23b435SEd Maste ("vtbuf_fill_locked begin.tp_col %d must be < screen width %d", 33727cf7d04SAleksandr Rybalko r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 33827cf7d04SAleksandr Rybalko 33927cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 340ba23b435SEd Maste ("vtbuf_fill_locked end.tp_row %d must be <= screen height %d", 34127cf7d04SAleksandr Rybalko r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 34227cf7d04SAleksandr Rybalko KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 343ba23b435SEd Maste ("vtbuf_fill_locked end.tp_col %d must be <= screen width %d", 34427cf7d04SAleksandr Rybalko r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 34527cf7d04SAleksandr Rybalko 34627cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 34727cf7d04SAleksandr Rybalko vtbuf_fill(vb, r, c); 34800c33067SJean-Sébastien Pédron vtbuf_dirty_locked(vb, r); 34927cf7d04SAleksandr Rybalko VTBUF_UNLOCK(vb); 35027cf7d04SAleksandr Rybalko } 35127cf7d04SAleksandr Rybalko 35227cf7d04SAleksandr Rybalko static void 35327cf7d04SAleksandr Rybalko vtbuf_init_rows(struct vt_buf *vb) 35427cf7d04SAleksandr Rybalko { 35527cf7d04SAleksandr Rybalko int r; 35627cf7d04SAleksandr Rybalko 35727cf7d04SAleksandr Rybalko vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 35827cf7d04SAleksandr Rybalko 35927cf7d04SAleksandr Rybalko for (r = 0; r < vb->vb_history_size; r++) 3607344ee18SMarius Strobl vb->vb_rows[r] = &vb->vb_buffer[r * vb->vb_scr_size.tp_col]; 36127cf7d04SAleksandr Rybalko } 36227cf7d04SAleksandr Rybalko 36327cf7d04SAleksandr Rybalko void 36427cf7d04SAleksandr Rybalko vtbuf_init_early(struct vt_buf *vb) 36527cf7d04SAleksandr Rybalko { 3667344ee18SMarius Strobl term_rect_t rect; 36727cf7d04SAleksandr Rybalko 36827cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_CURSOR; 36927cf7d04SAleksandr Rybalko vb->vb_roffset = 0; 37027cf7d04SAleksandr Rybalko vb->vb_curroffset = 0; 37127cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = 0; 37227cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = 0; 37327cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = 0; 37427cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = 0; 37527cf7d04SAleksandr Rybalko 37627cf7d04SAleksandr Rybalko vtbuf_init_rows(vb); 3777344ee18SMarius Strobl rect.tr_begin.tp_row = rect.tr_begin.tp_col = 0; 378cb81897aSJean-Sébastien Pédron rect.tr_end.tp_col = vb->vb_scr_size.tp_col; 379cb81897aSJean-Sébastien Pédron rect.tr_end.tp_row = vb->vb_history_size; 380cb81897aSJean-Sébastien Pédron vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR)); 38127cf7d04SAleksandr Rybalko vtbuf_make_undirty(vb); 38227cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 38327cf7d04SAleksandr Rybalko mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 38427cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_MTX_INIT; 38527cf7d04SAleksandr Rybalko } 38627cf7d04SAleksandr Rybalko } 38727cf7d04SAleksandr Rybalko 38827cf7d04SAleksandr Rybalko void 38927cf7d04SAleksandr Rybalko vtbuf_init(struct vt_buf *vb, const term_pos_t *p) 39027cf7d04SAleksandr Rybalko { 39127cf7d04SAleksandr Rybalko int sz; 39227cf7d04SAleksandr Rybalko 39327cf7d04SAleksandr Rybalko vb->vb_scr_size = *p; 39427cf7d04SAleksandr Rybalko vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 39527cf7d04SAleksandr Rybalko 39627cf7d04SAleksandr Rybalko if ((vb->vb_flags & VBF_STATIC) == 0) { 39727cf7d04SAleksandr Rybalko sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 39827cf7d04SAleksandr Rybalko vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 39927cf7d04SAleksandr Rybalko 40027cf7d04SAleksandr Rybalko sz = vb->vb_history_size * sizeof(term_char_t *); 40127cf7d04SAleksandr Rybalko vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 40227cf7d04SAleksandr Rybalko } 40327cf7d04SAleksandr Rybalko 40427cf7d04SAleksandr Rybalko vtbuf_init_early(vb); 40527cf7d04SAleksandr Rybalko } 40627cf7d04SAleksandr Rybalko 40727cf7d04SAleksandr Rybalko void 40827cf7d04SAleksandr Rybalko vtbuf_sethistory_size(struct vt_buf *vb, int size) 40927cf7d04SAleksandr Rybalko { 41027cf7d04SAleksandr Rybalko term_pos_t p; 41127cf7d04SAleksandr Rybalko 41227cf7d04SAleksandr Rybalko /* With same size */ 41327cf7d04SAleksandr Rybalko p.tp_row = vb->vb_scr_size.tp_row; 41427cf7d04SAleksandr Rybalko p.tp_col = vb->vb_scr_size.tp_col; 41527cf7d04SAleksandr Rybalko vtbuf_grow(vb, &p, size); 41627cf7d04SAleksandr Rybalko } 41727cf7d04SAleksandr Rybalko 41827cf7d04SAleksandr Rybalko void 419b7fe4961SJean-Sébastien Pédron vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size) 42027cf7d04SAleksandr Rybalko { 421*1454439cSJean-Sébastien Pédron term_char_t *old, *new, **rows, **oldrows, **copyrows, *row, *oldrow; 422*1454439cSJean-Sébastien Pédron int bufsize, rowssize, w, h, c, r, history_was_full; 423*1454439cSJean-Sébastien Pédron unsigned int old_history_size; 42427cf7d04SAleksandr Rybalko term_rect_t rect; 42527cf7d04SAleksandr Rybalko 42627cf7d04SAleksandr Rybalko history_size = MAX(history_size, p->tp_row); 42727cf7d04SAleksandr Rybalko 42827cf7d04SAleksandr Rybalko /* Allocate new buffer. */ 42927cf7d04SAleksandr Rybalko bufsize = history_size * p->tp_col * sizeof(term_char_t); 43027cf7d04SAleksandr Rybalko new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 43127cf7d04SAleksandr Rybalko rowssize = history_size * sizeof(term_pos_t *); 43227cf7d04SAleksandr Rybalko rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 43327cf7d04SAleksandr Rybalko 43427cf7d04SAleksandr Rybalko /* Toggle it. */ 43527cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 43627cf7d04SAleksandr Rybalko old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 43727cf7d04SAleksandr Rybalko oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 43827cf7d04SAleksandr Rybalko copyrows = vb->vb_rows; 439*1454439cSJean-Sébastien Pédron 44027cf7d04SAleksandr Rybalko w = vb->vb_scr_size.tp_col; 441*1454439cSJean-Sébastien Pédron h = vb->vb_scr_size.tp_row; 442*1454439cSJean-Sébastien Pédron old_history_size = vb->vb_history_size; 443*1454439cSJean-Sébastien Pédron history_was_full = vb->vb_flags & VBF_HISTORY_FULL; 44427cf7d04SAleksandr Rybalko 44527cf7d04SAleksandr Rybalko vb->vb_history_size = history_size; 44627cf7d04SAleksandr Rybalko vb->vb_buffer = new; 44727cf7d04SAleksandr Rybalko vb->vb_rows = rows; 44827cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_STATIC; 44927cf7d04SAleksandr Rybalko vb->vb_scr_size = *p; 45027cf7d04SAleksandr Rybalko vtbuf_init_rows(vb); 45127cf7d04SAleksandr Rybalko 452*1454439cSJean-Sébastien Pédron /* Copy history and fill extra space if needed. */ 453*1454439cSJean-Sébastien Pédron if (history_size > old_history_size) { 454*1454439cSJean-Sébastien Pédron /* 455*1454439cSJean-Sébastien Pédron * Copy rows to the new buffer. The first row in the history 456*1454439cSJean-Sébastien Pédron * is back to index 0, ie. the new buffer doesn't cycle. 457*1454439cSJean-Sébastien Pédron * 458*1454439cSJean-Sébastien Pédron * The rest of the new buffer is initialized with blank 459*1454439cSJean-Sébastien Pédron * content. 460*1454439cSJean-Sébastien Pédron */ 461*1454439cSJean-Sébastien Pédron for (r = 0; r < old_history_size; r ++) { 462*1454439cSJean-Sébastien Pédron row = rows[r]; 463*1454439cSJean-Sébastien Pédron 464*1454439cSJean-Sébastien Pédron /* Compute the corresponding row in the old buffer. */ 465*1454439cSJean-Sébastien Pédron if (history_was_full) 466*1454439cSJean-Sébastien Pédron /* 467*1454439cSJean-Sébastien Pédron * The buffer is full, the "top" row is 468*1454439cSJean-Sébastien Pédron * the one just after the viewable area 469*1454439cSJean-Sébastien Pédron * (curroffset + viewable height) in the 470*1454439cSJean-Sébastien Pédron * cycling buffer. The corresponding row 471*1454439cSJean-Sébastien Pédron * is computed from this top row. 472*1454439cSJean-Sébastien Pédron */ 473*1454439cSJean-Sébastien Pédron oldrow = copyrows[ 474*1454439cSJean-Sébastien Pédron (vb->vb_curroffset + h + r) % 475*1454439cSJean-Sébastien Pédron old_history_size]; 476*1454439cSJean-Sébastien Pédron else 477*1454439cSJean-Sébastien Pédron /* 478*1454439cSJean-Sébastien Pédron * The buffer is not full, therefore, 479*1454439cSJean-Sébastien Pédron * we didn't cycle already. The 480*1454439cSJean-Sébastien Pédron * corresponding rows are the same in 481*1454439cSJean-Sébastien Pédron * both buffers. 482*1454439cSJean-Sébastien Pédron */ 483*1454439cSJean-Sébastien Pédron oldrow = copyrows[r]; 484*1454439cSJean-Sébastien Pédron 485*1454439cSJean-Sébastien Pédron memmove(row, oldrow, 486*1454439cSJean-Sébastien Pédron MIN(p->tp_col, w) * sizeof(term_char_t)); 487*1454439cSJean-Sébastien Pédron 4887344ee18SMarius Strobl /* 4897344ee18SMarius Strobl * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 4907344ee18SMarius Strobl * extended lines of kernel text using the wrong 4917344ee18SMarius Strobl * background color. 4927344ee18SMarius Strobl */ 493*1454439cSJean-Sébastien Pédron for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 494*1454439cSJean-Sébastien Pédron row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR); 49527cf7d04SAleksandr Rybalko } 496*1454439cSJean-Sébastien Pédron } 497*1454439cSJean-Sébastien Pédron 498*1454439cSJean-Sébastien Pédron /* Fill remaining rows. */ 49927cf7d04SAleksandr Rybalko rect.tr_begin.tp_col = 0; 500*1454439cSJean-Sébastien Pédron rect.tr_begin.tp_row = old_history_size; 50127cf7d04SAleksandr Rybalko rect.tr_end.tp_col = p->tp_col; 50227cf7d04SAleksandr Rybalko rect.tr_end.tp_row = p->tp_row; 503*1454439cSJean-Sébastien Pédron vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR)); 504*1454439cSJean-Sébastien Pédron 505*1454439cSJean-Sébastien Pédron vb->vb_flags &= ~VBF_HISTORY_FULL; 506*1454439cSJean-Sébastien Pédron } else { 507*1454439cSJean-Sébastien Pédron /* 508*1454439cSJean-Sébastien Pédron * Copy rows to the new buffer. The first row in the history 509*1454439cSJean-Sébastien Pédron * is back to index 0, ie. the new buffer doesn't cycle. 510*1454439cSJean-Sébastien Pédron * 511*1454439cSJean-Sébastien Pédron * (old_history_size - history_size) lines of history are 512*1454439cSJean-Sébastien Pédron * dropped. 513*1454439cSJean-Sébastien Pédron */ 514*1454439cSJean-Sébastien Pédron for (r = 0; r < history_size; r ++) { 515*1454439cSJean-Sébastien Pédron row = rows[r]; 516*1454439cSJean-Sébastien Pédron 517*1454439cSJean-Sébastien Pédron /* 518*1454439cSJean-Sébastien Pédron * Compute the corresponding row in the old buffer. 519*1454439cSJean-Sébastien Pédron * 520*1454439cSJean-Sébastien Pédron * See the equivalent if{} block above for an 521*1454439cSJean-Sébastien Pédron * explanation. 522*1454439cSJean-Sébastien Pédron */ 523*1454439cSJean-Sébastien Pédron if (history_was_full) 524*1454439cSJean-Sébastien Pédron oldrow = copyrows[ 525*1454439cSJean-Sébastien Pédron (vb->vb_curroffset + h + r + 526*1454439cSJean-Sébastien Pédron (old_history_size - history_size)) % 527*1454439cSJean-Sébastien Pédron old_history_size]; 528*1454439cSJean-Sébastien Pédron else 529*1454439cSJean-Sébastien Pédron oldrow = copyrows[ 530*1454439cSJean-Sébastien Pédron (r + (old_history_size - history_size)) % 531*1454439cSJean-Sébastien Pédron old_history_size]; 532*1454439cSJean-Sébastien Pédron 533*1454439cSJean-Sébastien Pédron memmove(row, oldrow, 534*1454439cSJean-Sébastien Pédron MIN(p->tp_col, w) * sizeof(term_char_t)); 535*1454439cSJean-Sébastien Pédron 536*1454439cSJean-Sébastien Pédron /* 537*1454439cSJean-Sébastien Pédron * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will 538*1454439cSJean-Sébastien Pédron * extended lines of kernel text using the wrong 539*1454439cSJean-Sébastien Pédron * background color. 540*1454439cSJean-Sébastien Pédron */ 541*1454439cSJean-Sébastien Pédron for (c = MIN(p->tp_col, w); c < p->tp_col; c++) { 542*1454439cSJean-Sébastien Pédron row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR); 54327cf7d04SAleksandr Rybalko } 54427cf7d04SAleksandr Rybalko } 545*1454439cSJean-Sébastien Pédron 546*1454439cSJean-Sébastien Pédron if (!history_was_full && 547*1454439cSJean-Sébastien Pédron (vb->vb_curroffset + h) >= history_size) 548*1454439cSJean-Sébastien Pédron vb->vb_flags |= VBF_HISTORY_FULL; 549*1454439cSJean-Sébastien Pédron } 550*1454439cSJean-Sébastien Pédron 551*1454439cSJean-Sébastien Pédron /* 552*1454439cSJean-Sébastien Pédron * If the screen is already filled (there are non-visible lines 553*1454439cSJean-Sébastien Pédron * above the current viewable area), adjust curroffset to the 554*1454439cSJean-Sébastien Pédron * new viewable area. 555*1454439cSJean-Sébastien Pédron */ 556*1454439cSJean-Sébastien Pédron if (!history_was_full && vb->vb_curroffset > 0) { 557*1454439cSJean-Sébastien Pédron vb->vb_curroffset = vb->vb_curroffset + h - p->tp_row; 558*1454439cSJean-Sébastien Pédron if (vb->vb_curroffset < 0) 559*1454439cSJean-Sébastien Pédron vb->vb_curroffset += vb->vb_history_size; 560*1454439cSJean-Sébastien Pédron vb->vb_curroffset %= vb->vb_history_size; 561*1454439cSJean-Sébastien Pédron vb->vb_roffset = vb->vb_curroffset; 562*1454439cSJean-Sébastien Pédron } 563*1454439cSJean-Sébastien Pédron 56427cf7d04SAleksandr Rybalko vtbuf_make_undirty(vb); 56527cf7d04SAleksandr Rybalko VTBUF_UNLOCK(vb); 566*1454439cSJean-Sébastien Pédron 56727cf7d04SAleksandr Rybalko /* Deallocate old buffer. */ 56827cf7d04SAleksandr Rybalko free(old, M_VTBUF); 56927cf7d04SAleksandr Rybalko free(oldrows, M_VTBUF); 57027cf7d04SAleksandr Rybalko } 57127cf7d04SAleksandr Rybalko 57227cf7d04SAleksandr Rybalko void 57327cf7d04SAleksandr Rybalko vtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 57427cf7d04SAleksandr Rybalko { 57527cf7d04SAleksandr Rybalko term_char_t *row; 57627cf7d04SAleksandr Rybalko 57727cf7d04SAleksandr Rybalko KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 57827cf7d04SAleksandr Rybalko ("vtbuf_putchar tp_row %d must be less than screen width %d", 57927cf7d04SAleksandr Rybalko p->tp_row, vb->vb_scr_size.tp_row)); 58027cf7d04SAleksandr Rybalko KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 58127cf7d04SAleksandr Rybalko ("vtbuf_putchar tp_col %d must be less than screen height %d", 58227cf7d04SAleksandr Rybalko p->tp_col, vb->vb_scr_size.tp_col)); 58327cf7d04SAleksandr Rybalko 58427cf7d04SAleksandr Rybalko row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 58527cf7d04SAleksandr Rybalko VTBUF_MAX_HEIGHT(vb)]; 58627cf7d04SAleksandr Rybalko if (row[p->tp_col] != c) { 58727cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 58827cf7d04SAleksandr Rybalko row[p->tp_col] = c; 58900c33067SJean-Sébastien Pédron vtbuf_dirty_cell_locked(vb, p); 59027cf7d04SAleksandr Rybalko VTBUF_UNLOCK(vb); 59127cf7d04SAleksandr Rybalko } 59227cf7d04SAleksandr Rybalko } 59327cf7d04SAleksandr Rybalko 59427cf7d04SAleksandr Rybalko void 59527cf7d04SAleksandr Rybalko vtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 59627cf7d04SAleksandr Rybalko { 59727cf7d04SAleksandr Rybalko 59827cf7d04SAleksandr Rybalko if (vb->vb_flags & VBF_CURSOR) { 59900c33067SJean-Sébastien Pédron VTBUF_LOCK(vb); 60000c33067SJean-Sébastien Pédron vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 60127cf7d04SAleksandr Rybalko vb->vb_cursor = *p; 60200c33067SJean-Sébastien Pédron vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 60300c33067SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 60427cf7d04SAleksandr Rybalko } else { 60527cf7d04SAleksandr Rybalko vb->vb_cursor = *p; 60627cf7d04SAleksandr Rybalko } 60727cf7d04SAleksandr Rybalko } 60827cf7d04SAleksandr Rybalko 6090f49db6eSAleksandr Rybalko #ifndef SC_NO_CUTPASTE 61027cf7d04SAleksandr Rybalko static void 61127cf7d04SAleksandr Rybalko vtbuf_flush_mark(struct vt_buf *vb) 61227cf7d04SAleksandr Rybalko { 61327cf7d04SAleksandr Rybalko term_rect_t area; 61427cf7d04SAleksandr Rybalko int s, e; 61527cf7d04SAleksandr Rybalko 61627cf7d04SAleksandr Rybalko /* Notify renderer to update marked region. */ 61727cf7d04SAleksandr Rybalko if (vb->vb_mark_start.tp_col || vb->vb_mark_end.tp_col || 61827cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row || vb->vb_mark_end.tp_row) { 61927cf7d04SAleksandr Rybalko 62027cf7d04SAleksandr Rybalko s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 62127cf7d04SAleksandr Rybalko e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 62227cf7d04SAleksandr Rybalko 62327cf7d04SAleksandr Rybalko area.tr_begin.tp_col = 0; 62427cf7d04SAleksandr Rybalko area.tr_begin.tp_row = MIN(s, e); 62527cf7d04SAleksandr Rybalko 62627cf7d04SAleksandr Rybalko area.tr_end.tp_col = vb->vb_scr_size.tp_col; 62727cf7d04SAleksandr Rybalko area.tr_end.tp_row = MAX(s, e) + 1; 62827cf7d04SAleksandr Rybalko 62927cf7d04SAleksandr Rybalko vtbuf_dirty(vb, &area); 63027cf7d04SAleksandr Rybalko } 63127cf7d04SAleksandr Rybalko } 63227cf7d04SAleksandr Rybalko 63327cf7d04SAleksandr Rybalko int 63427cf7d04SAleksandr Rybalko vtbuf_get_marked_len(struct vt_buf *vb) 63527cf7d04SAleksandr Rybalko { 63627cf7d04SAleksandr Rybalko int ei, si, sz; 63727cf7d04SAleksandr Rybalko term_pos_t s, e; 63827cf7d04SAleksandr Rybalko 63927cf7d04SAleksandr Rybalko /* Swap according to window coordinates. */ 64027cf7d04SAleksandr Rybalko if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 64127cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col) > 64227cf7d04SAleksandr Rybalko POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 64327cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col)) { 64427cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_start); 64527cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_end); 64627cf7d04SAleksandr Rybalko } else { 64727cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_start); 64827cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_end); 64927cf7d04SAleksandr Rybalko } 65027cf7d04SAleksandr Rybalko 65127cf7d04SAleksandr Rybalko si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 65227cf7d04SAleksandr Rybalko ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 65327cf7d04SAleksandr Rybalko 65427cf7d04SAleksandr Rybalko /* Number symbols and number of rows to inject \n */ 65544f751a2SAleksandr Rybalko sz = ei - si + ((e.tp_row - s.tp_row) * 2); 65627cf7d04SAleksandr Rybalko 65727cf7d04SAleksandr Rybalko return (sz * sizeof(term_char_t)); 65827cf7d04SAleksandr Rybalko } 65927cf7d04SAleksandr Rybalko 66027cf7d04SAleksandr Rybalko void 66127cf7d04SAleksandr Rybalko vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 66227cf7d04SAleksandr Rybalko { 66327cf7d04SAleksandr Rybalko int i, r, c, cs, ce; 66427cf7d04SAleksandr Rybalko term_pos_t s, e; 66527cf7d04SAleksandr Rybalko 66627cf7d04SAleksandr Rybalko /* Swap according to window coordinates. */ 66727cf7d04SAleksandr Rybalko if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 66827cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col) > 66927cf7d04SAleksandr Rybalko POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 67027cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col)) { 67127cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_start); 67227cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_end); 67327cf7d04SAleksandr Rybalko } else { 67427cf7d04SAleksandr Rybalko POS_COPY(s, vb->vb_mark_start); 67527cf7d04SAleksandr Rybalko POS_COPY(e, vb->vb_mark_end); 67627cf7d04SAleksandr Rybalko } 67727cf7d04SAleksandr Rybalko 67827cf7d04SAleksandr Rybalko i = 0; 67927cf7d04SAleksandr Rybalko for (r = s.tp_row; r <= e.tp_row; r ++) { 68027cf7d04SAleksandr Rybalko cs = (r == s.tp_row)?s.tp_col:0; 68127cf7d04SAleksandr Rybalko ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 68227cf7d04SAleksandr Rybalko for (c = cs; c < ce; c ++) { 68327cf7d04SAleksandr Rybalko buf[i++] = vb->vb_rows[r][c]; 68427cf7d04SAleksandr Rybalko } 68527cf7d04SAleksandr Rybalko /* Add new line for all rows, but not for last one. */ 68627cf7d04SAleksandr Rybalko if (r != e.tp_row) { 68727cf7d04SAleksandr Rybalko buf[i++] = '\r'; 68827cf7d04SAleksandr Rybalko buf[i++] = '\n'; 68927cf7d04SAleksandr Rybalko } 69027cf7d04SAleksandr Rybalko } 69127cf7d04SAleksandr Rybalko } 69227cf7d04SAleksandr Rybalko 69327cf7d04SAleksandr Rybalko int 69427cf7d04SAleksandr Rybalko vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 69527cf7d04SAleksandr Rybalko { 69627cf7d04SAleksandr Rybalko term_char_t *r; 69727cf7d04SAleksandr Rybalko int i; 69827cf7d04SAleksandr Rybalko 69927cf7d04SAleksandr Rybalko switch (type) { 70027cf7d04SAleksandr Rybalko case VTB_MARK_END: /* B1 UP */ 70127cf7d04SAleksandr Rybalko if (vb->vb_mark_last != VTB_MARK_MOVE) 70227cf7d04SAleksandr Rybalko return (0); 70327cf7d04SAleksandr Rybalko /* FALLTHROUGH */ 70427cf7d04SAleksandr Rybalko case VTB_MARK_MOVE: 70527cf7d04SAleksandr Rybalko case VTB_MARK_EXTEND: 70627cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 70727cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = col; 70827cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 70927cf7d04SAleksandr Rybalko break; 71027cf7d04SAleksandr Rybalko case VTB_MARK_START: 71127cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 71227cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = col; 71327cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 71427cf7d04SAleksandr Rybalko /* Start again, so clear end point. */ 71527cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = col; 71627cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 71727cf7d04SAleksandr Rybalko break; 71827cf7d04SAleksandr Rybalko case VTB_MARK_WORD: 71927cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 72027cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 72127cf7d04SAleksandr Rybalko vtbuf_wth(vb, row); 72227cf7d04SAleksandr Rybalko r = vb->vb_rows[vb->vb_mark_start.tp_row]; 72327cf7d04SAleksandr Rybalko for (i = col; i >= 0; i --) { 72427cf7d04SAleksandr Rybalko if (TCHAR_CHARACTER(r[i]) == ' ') { 72527cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = i + 1; 72627cf7d04SAleksandr Rybalko break; 72727cf7d04SAleksandr Rybalko } 72827cf7d04SAleksandr Rybalko } 72927cf7d04SAleksandr Rybalko for (i = col; i < vb->vb_scr_size.tp_col; i ++) { 73027cf7d04SAleksandr Rybalko if (TCHAR_CHARACTER(r[i]) == ' ') { 73127cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = i; 73227cf7d04SAleksandr Rybalko break; 73327cf7d04SAleksandr Rybalko } 73427cf7d04SAleksandr Rybalko } 73527cf7d04SAleksandr Rybalko if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col) 73627cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 73727cf7d04SAleksandr Rybalko break; 73827cf7d04SAleksandr Rybalko case VTB_MARK_ROW: 73927cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); /* Clean old mark. */ 74027cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_col = 0; 74127cf7d04SAleksandr Rybalko vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 74227cf7d04SAleksandr Rybalko vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 74327cf7d04SAleksandr Rybalko vtbuf_wth(vb, row); 74427cf7d04SAleksandr Rybalko break; 74527cf7d04SAleksandr Rybalko case VTB_MARK_NONE: 74627cf7d04SAleksandr Rybalko vb->vb_mark_last = type; 74727cf7d04SAleksandr Rybalko /* FALLTHROUGH */ 74827cf7d04SAleksandr Rybalko default: 74927cf7d04SAleksandr Rybalko /* panic? */ 75027cf7d04SAleksandr Rybalko return (0); 75127cf7d04SAleksandr Rybalko } 75227cf7d04SAleksandr Rybalko 75327cf7d04SAleksandr Rybalko vb->vb_mark_last = type; 75427cf7d04SAleksandr Rybalko /* Draw new marked region. */ 75527cf7d04SAleksandr Rybalko vtbuf_flush_mark(vb); 75627cf7d04SAleksandr Rybalko return (1); 75727cf7d04SAleksandr Rybalko } 7580f49db6eSAleksandr Rybalko #endif 75927cf7d04SAleksandr Rybalko 76027cf7d04SAleksandr Rybalko void 76127cf7d04SAleksandr Rybalko vtbuf_cursor_visibility(struct vt_buf *vb, int yes) 76227cf7d04SAleksandr Rybalko { 76327cf7d04SAleksandr Rybalko int oflags, nflags; 76427cf7d04SAleksandr Rybalko 76527cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 76627cf7d04SAleksandr Rybalko oflags = vb->vb_flags; 76727cf7d04SAleksandr Rybalko if (yes) 76827cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_CURSOR; 76927cf7d04SAleksandr Rybalko else 77027cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_CURSOR; 77127cf7d04SAleksandr Rybalko nflags = vb->vb_flags; 77227cf7d04SAleksandr Rybalko 77327cf7d04SAleksandr Rybalko if (oflags != nflags) 77400c33067SJean-Sébastien Pédron vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 77500c33067SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 77627cf7d04SAleksandr Rybalko } 77727cf7d04SAleksandr Rybalko 77827cf7d04SAleksandr Rybalko void 77927cf7d04SAleksandr Rybalko vtbuf_scroll_mode(struct vt_buf *vb, int yes) 78027cf7d04SAleksandr Rybalko { 78127cf7d04SAleksandr Rybalko int oflags, nflags; 78227cf7d04SAleksandr Rybalko 78327cf7d04SAleksandr Rybalko VTBUF_LOCK(vb); 78427cf7d04SAleksandr Rybalko oflags = vb->vb_flags; 78527cf7d04SAleksandr Rybalko if (yes) 78627cf7d04SAleksandr Rybalko vb->vb_flags |= VBF_SCROLL; 78727cf7d04SAleksandr Rybalko else 78827cf7d04SAleksandr Rybalko vb->vb_flags &= ~VBF_SCROLL; 78927cf7d04SAleksandr Rybalko nflags = vb->vb_flags; 79027cf7d04SAleksandr Rybalko 79127cf7d04SAleksandr Rybalko if (oflags != nflags) 79200c33067SJean-Sébastien Pédron vtbuf_dirty_cell_locked(vb, &vb->vb_cursor); 79300c33067SJean-Sébastien Pédron VTBUF_UNLOCK(vb); 79427cf7d04SAleksandr Rybalko } 79527cf7d04SAleksandr Rybalko 796