1219888Sed/*- 2257547Sray * Copyright (c) 2009, 2013 The FreeBSD Foundation 3219888Sed * All rights reserved. 4219888Sed * 5219888Sed * This software was developed by Ed Schouten under sponsorship from the 6219888Sed * FreeBSD Foundation. 7219888Sed * 8257547Sray * Portions of this software were developed by Oleksandr Rybalko 9257547Sray * under sponsorship from the FreeBSD Foundation. 10257547Sray * 11219888Sed * Redistribution and use in source and binary forms, with or without 12219888Sed * modification, are permitted provided that the following conditions 13219888Sed * are met: 14219888Sed * 1. Redistributions of source code must retain the above copyright 15219888Sed * notice, this list of conditions and the following disclaimer. 16219888Sed * 2. Redistributions in binary form must reproduce the above copyright 17219888Sed * notice, this list of conditions and the following disclaimer in the 18219888Sed * documentation and/or other materials provided with the distribution. 19219888Sed * 20219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23219888Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30219888Sed * SUCH DAMAGE. 31219888Sed */ 32219888Sed 33219888Sed#include <sys/cdefs.h> 34219888Sed__FBSDID("$FreeBSD$"); 35219888Sed 36219888Sed#include <sys/param.h> 37219888Sed#include <sys/kernel.h> 38219888Sed#include <sys/lock.h> 39219888Sed#include <sys/malloc.h> 40219888Sed#include <sys/mutex.h> 41219888Sed#include <sys/systm.h> 42219888Sed 43219888Sed#include <dev/vt/vt.h> 44219888Sed 45219888Sedstatic MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); 46219888Sed 47219888Sed#define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) 48219888Sed#define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) 49257971Sray 50258090Sray#define POS_INDEX(c, r) (((r) << 12) + (c)) 51258090Sray#define POS_COPY(d, s) do { \ 52258090Sray (d).tp_col = (s).tp_col; \ 53258090Sray (d).tp_row = (s).tp_row; \ 54258090Sray} while (0) 55257971Sray 56258090Sray 57256145Sray/* 58256145Sray * line4 59256145Sray * line5 <--- curroffset (terminal output to that line) 60256145Sray * line0 61256145Sray * line1 <--- roffset (history display from that point) 62256145Sray * line2 63256145Sray * line3 64256145Sray */ 65256145Srayint 66256145Srayvthistory_seek(struct vt_buf *vb, int offset, int whence) 67256145Sray{ 68257074Sray int diff, top, bottom, roffset; 69219888Sed 70256145Sray /* No scrolling if not enabled. */ 71256145Sray if ((vb->vb_flags & VBF_SCROLL) == 0) { 72256145Sray if (vb->vb_roffset != vb->vb_curroffset) { 73256145Sray vb->vb_roffset = vb->vb_curroffset; 74257074Sray return (0xffff); 75256145Sray } 76256145Sray return (0); /* No changes */ 77256145Sray } 78256970Sray top = (vb->vb_flags & VBF_HISTORY_FULL)? 79256970Sray (vb->vb_curroffset + vb->vb_scr_size.tp_row):vb->vb_history_size; 80256970Sray bottom = vb->vb_curroffset + vb->vb_history_size; 81256970Sray 82256145Sray /* 83256145Sray * Operate on copy of offset value, since it temporary can be bigger 84256145Sray * than amount of rows in buffer. 85256145Sray */ 86256970Sray roffset = vb->vb_roffset + vb->vb_history_size; 87256145Sray switch (whence) { 88256145Sray case VHS_SET: 89257074Sray roffset = offset + vb->vb_history_size; 90256145Sray break; 91256145Sray case VHS_CUR: 92256145Sray roffset += offset; 93256145Sray break; 94256145Sray case VHS_END: 95256145Sray /* Go to current offset. */ 96257074Sray roffset = vb->vb_curroffset + vb->vb_history_size; 97256145Sray break; 98256145Sray } 99256145Sray 100256970Sray roffset = (roffset < top)?top:roffset; 101256970Sray roffset = (roffset > bottom)?bottom:roffset; 102256145Sray 103256970Sray roffset %= vb->vb_history_size; 104256970Sray 105256145Sray if (vb->vb_roffset != roffset) { 106257074Sray diff = vb->vb_roffset - roffset; 107256145Sray vb->vb_roffset = roffset; 108257074Sray /* 109257074Sray * Offset changed, please update Nth lines on sceen. 110257074Sray * +N - Nth lines at top; 111257074Sray * -N - Nth lines at bottom. 112257074Sray */ 113257074Sray return (diff); 114256145Sray } 115256145Sray return (0); /* No changes */ 116256145Sray} 117256145Sray 118256145Srayvoid 119256145Srayvthistory_addlines(struct vt_buf *vb, int offset) 120256145Sray{ 121256145Sray 122256145Sray vb->vb_curroffset += offset; 123256145Sray if (vb->vb_curroffset < 0) 124256145Sray vb->vb_curroffset = 0; 125256145Sray vb->vb_curroffset %= vb->vb_history_size; 126256145Sray if ((vb->vb_flags & VBF_SCROLL) == 0) { 127256145Sray vb->vb_roffset = vb->vb_curroffset; 128256145Sray } 129256145Sray} 130256145Sray 131256145Srayvoid 132256145Srayvthistory_getpos(const struct vt_buf *vb, unsigned int *offset) 133256145Sray{ 134256145Sray 135256145Sray *offset = vb->vb_roffset; 136256145Sray} 137256145Sray 138263817Sray#ifndef SC_NO_CUTPASTE /* Only mouse support use it now. */ 139258090Sray/* Translate current view row number to history row. */ 140258090Sraystatic int 141258090Srayvtbuf_wth(struct vt_buf *vb, int row) 142258090Sray{ 143258090Sray 144258090Sray return ((vb->vb_roffset + row) % vb->vb_history_size); 145258090Sray} 146263817Sray#endif 147258090Sray 148258090Sray/* Translate history row to current view row number. */ 149258090Sraystatic int 150258090Srayvtbuf_htw(struct vt_buf *vb, int row) 151258090Sray{ 152258090Sray 153258090Sray /* 154258090Sray * total 1000 rows. 155258090Sray * History offset roffset winrow 156258090Sray * 205 200 ((205 - 200 + 1000) % 1000) = 5 157258090Sray * 90 990 ((90 - 990 + 1000) % 1000) = 100 158258090Sray */ 159258090Sray return ((row - vb->vb_roffset + vb->vb_history_size) % 160258090Sray vb->vb_history_size); 161258090Sray} 162258090Sray 163257971Srayint 164257971Srayvtbuf_iscursor(struct vt_buf *vb, int row, int col) 165257971Sray{ 166258090Sray int sc, sr, ec, er, tmp; 167258090Sray 168258090Sray if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 169258090Sray (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 170257971Sray return (1); 171257971Sray 172258090Sray /* Mark cut/paste region. */ 173258090Sray 174258090Sray /* 175258090Sray * Luckily screen view is not like circular buffer, so we will 176258090Sray * calculate in screen coordinates. Translate first. 177258090Sray */ 178258090Sray sc = vb->vb_mark_start.tp_col; 179258090Sray sr = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 180258090Sray ec = vb->vb_mark_end.tp_col; 181258090Sray er = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 182258090Sray 183258090Sray 184258090Sray /* Swap start and end if start > end. */ 185258090Sray if (POS_INDEX(sc, sr) > POS_INDEX(ec, er)) { 186258090Sray tmp = sc; sc = ec; ec = tmp; 187258090Sray tmp = sr; sr = er; er = tmp; 188258090Sray } 189258090Sray 190258090Sray if ((POS_INDEX(sc, sr) <= POS_INDEX(col, row)) && 191258090Sray (POS_INDEX(col, row) < POS_INDEX(ec, er))) 192257971Sray return (1); 193257971Sray 194257971Sray return (0); 195257971Sray} 196257971Sray 197219888Sedstatic inline uint64_t 198219888Sedvtbuf_dirty_axis(unsigned int begin, unsigned int end) 199219888Sed{ 200219888Sed uint64_t left, right, mask; 201219888Sed 202219888Sed /* 203219888Sed * Mark all bits between begin % 64 and end % 64 dirty. 204219888Sed * This code is functionally equivalent to: 205219888Sed * 206219888Sed * for (i = begin; i < end; i++) 207219888Sed * mask |= (uint64_t)1 << (i % 64); 208219888Sed */ 209219888Sed 210219888Sed /* Obvious case. Mark everything dirty. */ 211219888Sed if (end - begin >= 64) 212219888Sed return (VBM_DIRTY); 213219888Sed 214219888Sed /* 1....0; used bits on the left. */ 215219888Sed left = VBM_DIRTY << begin % 64; 216219888Sed /* 0....1; used bits on the right. */ 217219888Sed right = VBM_DIRTY >> -end % 64; 218219888Sed 219219888Sed /* 220219888Sed * Only take the intersection. If the result of that is 0, it 221219888Sed * means that the selection crossed a 64 bit boundary along the 222219888Sed * way, which means we have to take the complement. 223219888Sed */ 224219888Sed mask = left & right; 225219888Sed if (mask == 0) 226219888Sed mask = left | right; 227219888Sed return (mask); 228219888Sed} 229219888Sed 230219888Sedstatic inline void 231219888Sedvtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 232219888Sed{ 233219888Sed 234219888Sed VTBUF_LOCK(vb); 235219888Sed if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 236219888Sed vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 237219888Sed if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 238219888Sed vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 239219888Sed if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 240219888Sed vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 241219888Sed if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 242219888Sed vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 243219888Sed vb->vb_dirtymask.vbm_row |= 244219888Sed vtbuf_dirty_axis(area->tr_begin.tp_row, area->tr_end.tp_row); 245219888Sed vb->vb_dirtymask.vbm_col |= 246219888Sed vtbuf_dirty_axis(area->tr_begin.tp_col, area->tr_end.tp_col); 247219888Sed VTBUF_UNLOCK(vb); 248219888Sed} 249219888Sed 250219888Sedstatic inline void 251219888Sedvtbuf_dirty_cell(struct vt_buf *vb, const term_pos_t *p) 252219888Sed{ 253219888Sed term_rect_t area; 254219888Sed 255219888Sed area.tr_begin = *p; 256219888Sed area.tr_end.tp_row = p->tp_row + 1; 257219888Sed area.tr_end.tp_col = p->tp_col + 1; 258219888Sed vtbuf_dirty(vb, &area); 259219888Sed} 260219888Sed 261219888Sedstatic void 262219888Sedvtbuf_make_undirty(struct vt_buf *vb) 263219888Sed{ 264219888Sed 265256145Sray vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 266219888Sed vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 267219888Sed vb->vb_dirtymask.vbm_row = vb->vb_dirtymask.vbm_col = 0; 268219888Sed} 269219888Sed 270219888Sedvoid 271219888Sedvtbuf_undirty(struct vt_buf *vb, term_rect_t *r, struct vt_bufmask *m) 272219888Sed{ 273219888Sed 274219888Sed VTBUF_LOCK(vb); 275219888Sed *r = vb->vb_dirtyrect; 276219888Sed *m = vb->vb_dirtymask; 277219888Sed vtbuf_make_undirty(vb); 278219888Sed VTBUF_UNLOCK(vb); 279219888Sed} 280219888Sed 281219888Sedvoid 282219888Sedvtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 283219888Sed{ 284219888Sed const term_pos_t *p1 = &r->tr_begin; 285219888Sed term_rect_t area; 286219888Sed unsigned int rows, cols; 287256145Sray int pr, rdiff; 288219888Sed 289256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 290256145Sray ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 291256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 292256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 293256145Sray ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 294256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 295256145Sray 296256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 297256145Sray ("vtbuf_copy end.tp_row %d must be less than screen width %d", 298256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 299256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 300256145Sray ("vtbuf_copy end.tp_col %d must be less than screen height %d", 301256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 302256145Sray 303256145Sray KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 304256145Sray ("vtbuf_copy tp_row %d must be less than screen width %d", 305256145Sray p2->tp_row, vb->vb_scr_size.tp_row)); 306256145Sray KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 307256145Sray ("vtbuf_copy tp_col %d must be less than screen height %d", 308256145Sray p2->tp_col, vb->vb_scr_size.tp_col)); 309256145Sray 310219888Sed rows = r->tr_end.tp_row - r->tr_begin.tp_row; 311256145Sray rdiff = r->tr_begin.tp_row - p2->tp_row; 312219888Sed cols = r->tr_end.tp_col - r->tr_begin.tp_col; 313256145Sray if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 314256145Sray r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 315256145Sray (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 316256145Sray rdiff > 0) { /* Only forward dirrection. Do not eat history. */ 317256145Sray vthistory_addlines(vb, rdiff); 318256145Sray } else if (p2->tp_row < p1->tp_row) { 319256145Sray /* Handle overlapping copies of line segments. */ 320219888Sed /* Move data up. */ 321219888Sed for (pr = 0; pr < rows; pr++) 322219888Sed memmove( 323219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 324219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 325219888Sed cols * sizeof(term_char_t)); 326219888Sed } else { 327219888Sed /* Move data down. */ 328219888Sed for (pr = rows - 1; pr >= 0; pr--) 329219888Sed memmove( 330219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 331219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 332219888Sed cols * sizeof(term_char_t)); 333219888Sed } 334219888Sed 335219888Sed area.tr_begin = *p2; 336256145Sray area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 337256145Sray area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 338219888Sed vtbuf_dirty(vb, &area); 339219888Sed} 340219888Sed 341256145Sraystatic void 342219888Sedvtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 343219888Sed{ 344219888Sed unsigned int pr, pc; 345256145Sray term_char_t *row; 346219888Sed 347256145Sray for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 348256145Sray row = vb->vb_rows[(vb->vb_curroffset + pr) % 349256145Sray VTBUF_MAX_HEIGHT(vb)]; 350256145Sray for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 351256145Sray row[pc] = c; 352256145Sray } 353256145Sray } 354256145Sray} 355219888Sed 356256145Srayvoid 357256145Srayvtbuf_fill_locked(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 358256145Sray{ 359256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 360256145Sray ("vtbuf_fill_locked begin.tp_row %d must be < screen width %d", 361256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 362256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 363256145Sray ("vtbuf_fill_locked begin.tp_col %d must be < screen height %d", 364256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 365256145Sray 366256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 367256145Sray ("vtbuf_fill_locked end.tp_row %d must be <= screen width %d", 368256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 369256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 370256145Sray ("vtbuf_fill_locked end.tp_col %d must be <= screen height %d", 371256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 372256145Sray 373256145Sray VTBUF_LOCK(vb); 374256145Sray vtbuf_fill(vb, r, c); 375256145Sray VTBUF_UNLOCK(vb); 376256145Sray 377219888Sed vtbuf_dirty(vb, r); 378219888Sed} 379219888Sed 380256145Sraystatic void 381256145Srayvtbuf_init_rows(struct vt_buf *vb) 382256145Sray{ 383256145Sray int r; 384256145Sray 385256145Sray vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 386256145Sray 387256145Sray for (r = 0; r < vb->vb_history_size; r++) 388256145Sray vb->vb_rows[r] = &vb->vb_buffer[r * 389256145Sray vb->vb_scr_size.tp_col]; 390256145Sray} 391256145Sray 392219888Sedvoid 393219888Sedvtbuf_init_early(struct vt_buf *vb) 394219888Sed{ 395219888Sed 396219888Sed vb->vb_flags |= VBF_CURSOR; 397256145Sray vb->vb_roffset = 0; 398256145Sray vb->vb_curroffset = 0; 399258090Sray vb->vb_mark_start.tp_row = 0; 400258090Sray vb->vb_mark_start.tp_col = 0; 401258090Sray vb->vb_mark_end.tp_row = 0; 402258090Sray vb->vb_mark_end.tp_col = 0; 403256145Sray 404256145Sray vtbuf_init_rows(vb); 405219888Sed vtbuf_make_undirty(vb); 406256145Sray if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 407256145Sray mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 408256145Sray vb->vb_flags |= VBF_MTX_INIT; 409256145Sray } 410219888Sed} 411219888Sed 412219888Sedvoid 413219888Sedvtbuf_init(struct vt_buf *vb, const term_pos_t *p) 414219888Sed{ 415256145Sray int sz; 416219888Sed 417256145Sray vb->vb_scr_size = *p; 418256145Sray vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 419256145Sray 420256145Sray if ((vb->vb_flags & VBF_STATIC) == 0) { 421256145Sray sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 422256894Sray vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 423256145Sray 424256145Sray sz = vb->vb_history_size * sizeof(term_char_t *); 425256894Sray vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 426256145Sray } 427256145Sray 428219888Sed vtbuf_init_early(vb); 429219888Sed} 430219888Sed 431219888Sedvoid 432256145Srayvtbuf_sethistory_size(struct vt_buf *vb, int size) 433219888Sed{ 434256145Sray term_pos_t p; 435219888Sed 436256145Sray /* With same size */ 437256145Sray p.tp_row = vb->vb_scr_size.tp_row; 438256145Sray p.tp_col = vb->vb_scr_size.tp_col; 439256145Sray vtbuf_grow(vb, &p, size); 440256145Sray} 441256145Sray 442256145Srayvoid 443256145Srayvtbuf_grow(struct vt_buf *vb, const term_pos_t *p, int history_size) 444256145Sray{ 445256145Sray term_char_t *old, *new, **rows, **oldrows, **copyrows, *row; 446256145Sray int bufsize, rowssize, w, h, c, r; 447256145Sray term_rect_t rect; 448256145Sray 449256145Sray history_size = MAX(history_size, p->tp_row); 450256145Sray 451256145Sray if (history_size > vb->vb_history_size || p->tp_col > 452256145Sray vb->vb_scr_size.tp_col) { 453219888Sed /* Allocate new buffer. */ 454256145Sray bufsize = history_size * p->tp_col * sizeof(term_char_t); 455256894Sray new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 456256145Sray rowssize = history_size * sizeof(term_pos_t *); 457256894Sray rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 458219888Sed 459219888Sed /* Toggle it. */ 460219888Sed VTBUF_LOCK(vb); 461219888Sed old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 462256145Sray oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 463256145Sray copyrows = vb->vb_rows; 464256145Sray w = vb->vb_scr_size.tp_col; 465256145Sray h = vb->vb_history_size; 466256145Sray 467256145Sray vb->vb_history_size = history_size; 468219888Sed vb->vb_buffer = new; 469256145Sray vb->vb_rows = rows; 470219888Sed vb->vb_flags &= ~VBF_STATIC; 471256145Sray vb->vb_scr_size = *p; 472256145Sray vtbuf_init_rows(vb); 473256145Sray 474256145Sray /* Copy history and fill extra space. */ 475256145Sray for (r = 0; r < history_size; r ++) { 476256145Sray row = rows[r]; 477256145Sray if (r < h) { /* Copy. */ 478256145Sray memmove(rows[r], copyrows[r], 479256145Sray MIN(p->tp_col, w) * sizeof(term_char_t)); 480256145Sray for (c = MIN(p->tp_col, w); c < p->tp_col; 481256145Sray c++) { 482256145Sray row[c] = VTBUF_SPACE_CHAR; 483256145Sray } 484256145Sray } else { /* Just fill. */ 485256145Sray rect.tr_begin.tp_col = 0; 486256145Sray rect.tr_begin.tp_row = r; 487256145Sray rect.tr_end.tp_col = p->tp_col; 488256145Sray rect.tr_end.tp_row = p->tp_row; 489256145Sray vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR); 490256145Sray break; 491256145Sray } 492256145Sray } 493219888Sed vtbuf_make_undirty(vb); 494219888Sed VTBUF_UNLOCK(vb); 495219888Sed /* Deallocate old buffer. */ 496256145Sray free(old, M_VTBUF); 497256145Sray free(oldrows, M_VTBUF); 498219888Sed } 499219888Sed} 500219888Sed 501219888Sedvoid 502219888Sedvtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 503219888Sed{ 504256145Sray term_char_t *row; 505219888Sed 506256145Sray KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 507256145Sray ("vtbuf_putchar tp_row %d must be less than screen width %d", 508256145Sray p->tp_row, vb->vb_scr_size.tp_row)); 509256145Sray KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 510256145Sray ("vtbuf_putchar tp_col %d must be less than screen height %d", 511256145Sray p->tp_col, vb->vb_scr_size.tp_col)); 512256145Sray 513256145Sray row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 514256145Sray VTBUF_MAX_HEIGHT(vb)]; 515256145Sray if (row[p->tp_col] != c) { 516256145Sray VTBUF_LOCK(vb); 517256145Sray row[p->tp_col] = c; 518256145Sray VTBUF_UNLOCK(vb); 519219888Sed vtbuf_dirty_cell(vb, p); 520219888Sed } 521219888Sed} 522219888Sed 523219888Sedvoid 524219888Sedvtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 525219888Sed{ 526219888Sed 527219888Sed if (vb->vb_flags & VBF_CURSOR) { 528219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 529219888Sed vb->vb_cursor = *p; 530219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 531219888Sed } else { 532219888Sed vb->vb_cursor = *p; 533219888Sed } 534219888Sed} 535219888Sed 536263817Sray#ifndef SC_NO_CUTPASTE 537219888Sedvoid 538257971Srayvtbuf_mouse_cursor_position(struct vt_buf *vb, int col, int row) 539257971Sray{ 540257971Sray term_rect_t area; 541257971Sray 542257971Sray area.tr_begin.tp_row = MAX(row - 1, 0); 543257971Sray area.tr_begin.tp_col = MAX(col - 1, 0); 544257971Sray area.tr_end.tp_row = MIN(row + 2, vb->vb_scr_size.tp_row); 545257971Sray area.tr_end.tp_col = MIN(col + 2, vb->vb_scr_size.tp_col); 546257971Sray vtbuf_dirty(vb, &area); 547257971Sray} 548257971Sray 549258090Sraystatic void 550258090Srayvtbuf_flush_mark(struct vt_buf *vb) 551258090Sray{ 552258090Sray term_rect_t area; 553258090Sray int s, e; 554258090Sray 555258090Sray /* Notify renderer to update marked region. */ 556258090Sray if (vb->vb_mark_start.tp_col || vb->vb_mark_end.tp_col || 557258090Sray vb->vb_mark_start.tp_row || vb->vb_mark_end.tp_row) { 558258090Sray 559258090Sray s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 560258090Sray e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 561258090Sray 562258090Sray area.tr_begin.tp_col = 0; 563258090Sray area.tr_begin.tp_row = MIN(s, e); 564258090Sray 565258090Sray area.tr_end.tp_col = vb->vb_scr_size.tp_col; 566258090Sray area.tr_end.tp_row = MAX(s, e) + 1; 567258090Sray 568258090Sray vtbuf_dirty(vb, &area); 569258090Sray } 570258090Sray} 571258090Sray 572258090Srayint 573258090Srayvtbuf_get_marked_len(struct vt_buf *vb) 574258090Sray{ 575258090Sray int ei, si, sz; 576258090Sray term_pos_t s, e; 577258090Sray 578258090Sray /* Swap according to window coordinates. */ 579258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 580258134Sray vb->vb_mark_start.tp_col) > 581258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 582258134Sray vb->vb_mark_end.tp_col)) { 583258090Sray POS_COPY(e, vb->vb_mark_start); 584258090Sray POS_COPY(s, vb->vb_mark_end); 585258090Sray } else { 586258090Sray POS_COPY(s, vb->vb_mark_start); 587258090Sray POS_COPY(e, vb->vb_mark_end); 588258090Sray } 589258090Sray 590258090Sray si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 591258090Sray ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 592258090Sray 593258090Sray /* Number symbols and number of rows to inject \n */ 594258090Sray sz = ei - si + ((e.tp_row - s.tp_row) * 2) + 1; 595258090Sray 596258090Sray return (sz * sizeof(term_char_t)); 597258090Sray} 598258090Sray 599257971Srayvoid 600258090Srayvtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 601258090Sray{ 602258090Sray int i, r, c, cs, ce; 603258090Sray term_pos_t s, e; 604258090Sray 605258090Sray /* Swap according to window coordinates. */ 606258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 607258134Sray vb->vb_mark_start.tp_col) > 608258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 609258134Sray vb->vb_mark_end.tp_col)) { 610258090Sray POS_COPY(e, vb->vb_mark_start); 611258090Sray POS_COPY(s, vb->vb_mark_end); 612258090Sray } else { 613258090Sray POS_COPY(s, vb->vb_mark_start); 614258090Sray POS_COPY(e, vb->vb_mark_end); 615258090Sray } 616258090Sray 617258090Sray i = 0; 618258090Sray for (r = s.tp_row; r <= e.tp_row; r ++) { 619258090Sray cs = (r == s.tp_row)?s.tp_col:0; 620258090Sray ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 621258090Sray for (c = cs; c < ce; c ++) { 622258090Sray buf[i++] = vb->vb_rows[r][c]; 623258090Sray } 624258093Sray /* Add new line for all rows, but not for last one. */ 625258093Sray if (r != e.tp_row) { 626258093Sray buf[i++] = '\r'; 627258093Sray buf[i++] = '\n'; 628258093Sray } 629258090Sray } 630258090Sray} 631258090Sray 632258090Srayint 633257971Srayvtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 634257971Sray{ 635258136Sray term_char_t *r; 636258136Sray int i; 637257971Sray 638257971Sray switch (type) { 639258130Sray case VTB_MARK_END: /* B1 UP */ 640258130Sray if (vb->vb_mark_last != VTB_MARK_MOVE) 641258130Sray return (0); 642258130Sray /* FALLTHROUGH */ 643258130Sray case VTB_MARK_MOVE: 644257971Sray case VTB_MARK_EXTEND: 645258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 646257971Sray vb->vb_mark_end.tp_col = col; 647258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 648257971Sray break; 649257971Sray case VTB_MARK_START: 650258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 651257971Sray vb->vb_mark_start.tp_col = col; 652258090Sray vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 653257971Sray /* Start again, so clear end point. */ 654258090Sray vb->vb_mark_end.tp_col = col; 655258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 656257971Sray break; 657257971Sray case VTB_MARK_WORD: 658258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 659258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 660258090Sray vtbuf_wth(vb, row); 661258136Sray r = vb->vb_rows[vb->vb_mark_start.tp_row]; 662258136Sray for (i = col; i >= 0; i --) { 663258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 664258136Sray vb->vb_mark_start.tp_col = i + 1; 665258136Sray break; 666258136Sray } 667258136Sray } 668258136Sray for (i = col; i < vb->vb_scr_size.tp_col; i ++) { 669258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 670258136Sray vb->vb_mark_end.tp_col = i; 671258136Sray break; 672258136Sray } 673258136Sray } 674258136Sray if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col) 675258136Sray vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 676257971Sray break; 677257971Sray case VTB_MARK_ROW: 678258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 679257971Sray vb->vb_mark_start.tp_col = 0; 680257971Sray vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 681258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 682258090Sray vtbuf_wth(vb, row); 683257971Sray break; 684258090Sray case VTB_MARK_NONE: 685258130Sray vb->vb_mark_last = type; 686258130Sray /* FALLTHROUGH */ 687258090Sray default: 688258090Sray /* panic? */ 689258090Sray return (0); 690257971Sray } 691258111Sray 692258130Sray vb->vb_mark_last = type; 693258111Sray /* Draw new marked region. */ 694258111Sray vtbuf_flush_mark(vb); 695258111Sray return (1); 696257971Sray} 697263817Sray#endif 698257971Sray 699257971Srayvoid 700219888Sedvtbuf_cursor_visibility(struct vt_buf *vb, int yes) 701219888Sed{ 702219888Sed int oflags, nflags; 703219888Sed 704219888Sed VTBUF_LOCK(vb); 705219888Sed oflags = vb->vb_flags; 706219888Sed if (yes) 707219888Sed vb->vb_flags |= VBF_CURSOR; 708219888Sed else 709219888Sed vb->vb_flags &= ~VBF_CURSOR; 710219888Sed nflags = vb->vb_flags; 711219888Sed VTBUF_UNLOCK(vb); 712219888Sed 713219888Sed if (oflags != nflags) 714219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 715219888Sed} 716258090Sray 717258090Srayvoid 718258090Srayvtbuf_scroll_mode(struct vt_buf *vb, int yes) 719258090Sray{ 720258090Sray int oflags, nflags; 721258090Sray 722258090Sray VTBUF_LOCK(vb); 723258090Sray oflags = vb->vb_flags; 724258090Sray if (yes) 725258090Sray vb->vb_flags |= VBF_SCROLL; 726258090Sray else 727258090Sray vb->vb_flags &= ~VBF_SCROLL; 728258090Sray nflags = vb->vb_flags; 729258090Sray VTBUF_UNLOCK(vb); 730258090Sray 731258090Sray if (oflags != nflags) 732258090Sray vtbuf_dirty_cell(vb, &vb->vb_cursor); 733258090Sray} 734258090Sray 735