vt_buf.c revision 258136
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: user/ed/newcons/sys/dev/vt/vt_buf.c 258136 2013-11-14 15:44:22Z ray $"); 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 138258090Sray/* Translate current view row number to history row. */ 139258090Sraystatic int 140258090Srayvtbuf_wth(struct vt_buf *vb, int row) 141258090Sray{ 142258090Sray 143258090Sray return ((vb->vb_roffset + row) % vb->vb_history_size); 144258090Sray} 145258090Sray 146258090Sray/* Translate history row to current view row number. */ 147258090Sraystatic int 148258090Srayvtbuf_htw(struct vt_buf *vb, int row) 149258090Sray{ 150258090Sray 151258090Sray /* 152258090Sray * total 1000 rows. 153258090Sray * History offset roffset winrow 154258090Sray * 205 200 ((205 - 200 + 1000) % 1000) = 5 155258090Sray * 90 990 ((90 - 990 + 1000) % 1000) = 100 156258090Sray */ 157258090Sray return ((row - vb->vb_roffset + vb->vb_history_size) % 158258090Sray vb->vb_history_size); 159258090Sray} 160258090Sray 161257971Srayint 162257971Srayvtbuf_iscursor(struct vt_buf *vb, int row, int col) 163257971Sray{ 164258090Sray int sc, sr, ec, er, tmp; 165258090Sray 166258090Sray if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 167258090Sray (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 168257971Sray return (1); 169257971Sray 170258090Sray /* Mark cut/paste region. */ 171258090Sray 172258090Sray /* 173258090Sray * Luckily screen view is not like circular buffer, so we will 174258090Sray * calculate in screen coordinates. Translate first. 175258090Sray */ 176258090Sray sc = vb->vb_mark_start.tp_col; 177258090Sray sr = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 178258090Sray ec = vb->vb_mark_end.tp_col; 179258090Sray er = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 180258090Sray 181258090Sray 182258090Sray /* Swap start and end if start > end. */ 183258090Sray if (POS_INDEX(sc, sr) > POS_INDEX(ec, er)) { 184258090Sray tmp = sc; sc = ec; ec = tmp; 185258090Sray tmp = sr; sr = er; er = tmp; 186258090Sray } 187258090Sray 188258090Sray if ((POS_INDEX(sc, sr) <= POS_INDEX(col, row)) && 189258090Sray (POS_INDEX(col, row) < POS_INDEX(ec, er))) 190257971Sray return (1); 191257971Sray 192257971Sray return (0); 193257971Sray} 194257971Sray 195219888Sedstatic inline uint64_t 196219888Sedvtbuf_dirty_axis(unsigned int begin, unsigned int end) 197219888Sed{ 198219888Sed uint64_t left, right, mask; 199219888Sed 200219888Sed /* 201219888Sed * Mark all bits between begin % 64 and end % 64 dirty. 202219888Sed * This code is functionally equivalent to: 203219888Sed * 204219888Sed * for (i = begin; i < end; i++) 205219888Sed * mask |= (uint64_t)1 << (i % 64); 206219888Sed */ 207219888Sed 208219888Sed /* Obvious case. Mark everything dirty. */ 209219888Sed if (end - begin >= 64) 210219888Sed return (VBM_DIRTY); 211219888Sed 212219888Sed /* 1....0; used bits on the left. */ 213219888Sed left = VBM_DIRTY << begin % 64; 214219888Sed /* 0....1; used bits on the right. */ 215219888Sed right = VBM_DIRTY >> -end % 64; 216219888Sed 217219888Sed /* 218219888Sed * Only take the intersection. If the result of that is 0, it 219219888Sed * means that the selection crossed a 64 bit boundary along the 220219888Sed * way, which means we have to take the complement. 221219888Sed */ 222219888Sed mask = left & right; 223219888Sed if (mask == 0) 224219888Sed mask = left | right; 225219888Sed return (mask); 226219888Sed} 227219888Sed 228219888Sedstatic inline void 229219888Sedvtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 230219888Sed{ 231219888Sed 232219888Sed VTBUF_LOCK(vb); 233219888Sed if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 234219888Sed vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 235219888Sed if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 236219888Sed vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 237219888Sed if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 238219888Sed vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 239219888Sed if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 240219888Sed vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 241219888Sed vb->vb_dirtymask.vbm_row |= 242219888Sed vtbuf_dirty_axis(area->tr_begin.tp_row, area->tr_end.tp_row); 243219888Sed vb->vb_dirtymask.vbm_col |= 244219888Sed vtbuf_dirty_axis(area->tr_begin.tp_col, area->tr_end.tp_col); 245219888Sed VTBUF_UNLOCK(vb); 246219888Sed} 247219888Sed 248219888Sedstatic inline void 249219888Sedvtbuf_dirty_cell(struct vt_buf *vb, const term_pos_t *p) 250219888Sed{ 251219888Sed term_rect_t area; 252219888Sed 253219888Sed area.tr_begin = *p; 254219888Sed area.tr_end.tp_row = p->tp_row + 1; 255219888Sed area.tr_end.tp_col = p->tp_col + 1; 256219888Sed vtbuf_dirty(vb, &area); 257219888Sed} 258219888Sed 259219888Sedstatic void 260219888Sedvtbuf_make_undirty(struct vt_buf *vb) 261219888Sed{ 262219888Sed 263256145Sray vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 264219888Sed vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 265219888Sed vb->vb_dirtymask.vbm_row = vb->vb_dirtymask.vbm_col = 0; 266219888Sed} 267219888Sed 268219888Sedvoid 269219888Sedvtbuf_undirty(struct vt_buf *vb, term_rect_t *r, struct vt_bufmask *m) 270219888Sed{ 271219888Sed 272219888Sed VTBUF_LOCK(vb); 273219888Sed *r = vb->vb_dirtyrect; 274219888Sed *m = vb->vb_dirtymask; 275219888Sed vtbuf_make_undirty(vb); 276219888Sed VTBUF_UNLOCK(vb); 277219888Sed} 278219888Sed 279219888Sedvoid 280219888Sedvtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 281219888Sed{ 282219888Sed const term_pos_t *p1 = &r->tr_begin; 283219888Sed term_rect_t area; 284219888Sed unsigned int rows, cols; 285256145Sray int pr, rdiff; 286219888Sed 287256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 288256145Sray ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 289256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 290256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 291256145Sray ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 292256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 293256145Sray 294256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 295256145Sray ("vtbuf_copy end.tp_row %d must be less than screen width %d", 296256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 297256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 298256145Sray ("vtbuf_copy end.tp_col %d must be less than screen height %d", 299256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 300256145Sray 301256145Sray KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 302256145Sray ("vtbuf_copy tp_row %d must be less than screen width %d", 303256145Sray p2->tp_row, vb->vb_scr_size.tp_row)); 304256145Sray KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 305256145Sray ("vtbuf_copy tp_col %d must be less than screen height %d", 306256145Sray p2->tp_col, vb->vb_scr_size.tp_col)); 307256145Sray 308219888Sed rows = r->tr_end.tp_row - r->tr_begin.tp_row; 309256145Sray rdiff = r->tr_begin.tp_row - p2->tp_row; 310219888Sed cols = r->tr_end.tp_col - r->tr_begin.tp_col; 311256145Sray if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 312256145Sray r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 313256145Sray (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 314256145Sray rdiff > 0) { /* Only forward dirrection. Do not eat history. */ 315256145Sray vthistory_addlines(vb, rdiff); 316256145Sray } else if (p2->tp_row < p1->tp_row) { 317256145Sray /* Handle overlapping copies of line segments. */ 318219888Sed /* Move data up. */ 319219888Sed for (pr = 0; pr < rows; pr++) 320219888Sed memmove( 321219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 322219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 323219888Sed cols * sizeof(term_char_t)); 324219888Sed } else { 325219888Sed /* Move data down. */ 326219888Sed for (pr = rows - 1; pr >= 0; pr--) 327219888Sed memmove( 328219888Sed &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 329219888Sed &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 330219888Sed cols * sizeof(term_char_t)); 331219888Sed } 332219888Sed 333219888Sed area.tr_begin = *p2; 334256145Sray area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 335256145Sray area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 336219888Sed vtbuf_dirty(vb, &area); 337219888Sed} 338219888Sed 339256145Sraystatic void 340219888Sedvtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 341219888Sed{ 342219888Sed unsigned int pr, pc; 343256145Sray term_char_t *row; 344219888Sed 345256145Sray for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 346256145Sray row = vb->vb_rows[(vb->vb_curroffset + pr) % 347256145Sray VTBUF_MAX_HEIGHT(vb)]; 348256145Sray for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 349256145Sray row[pc] = c; 350256145Sray } 351256145Sray } 352256145Sray} 353219888Sed 354256145Srayvoid 355256145Srayvtbuf_fill_locked(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 356256145Sray{ 357256145Sray KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 358256145Sray ("vtbuf_fill_locked begin.tp_row %d must be < screen width %d", 359256145Sray r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 360256145Sray KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 361256145Sray ("vtbuf_fill_locked begin.tp_col %d must be < screen height %d", 362256145Sray r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 363256145Sray 364256145Sray KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 365256145Sray ("vtbuf_fill_locked end.tp_row %d must be <= screen width %d", 366256145Sray r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 367256145Sray KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 368256145Sray ("vtbuf_fill_locked end.tp_col %d must be <= screen height %d", 369256145Sray r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 370256145Sray 371256145Sray VTBUF_LOCK(vb); 372256145Sray vtbuf_fill(vb, r, c); 373256145Sray VTBUF_UNLOCK(vb); 374256145Sray 375219888Sed vtbuf_dirty(vb, r); 376219888Sed} 377219888Sed 378256145Sraystatic void 379256145Srayvtbuf_init_rows(struct vt_buf *vb) 380256145Sray{ 381256145Sray int r; 382256145Sray 383256145Sray vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 384256145Sray 385256145Sray for (r = 0; r < vb->vb_history_size; r++) 386256145Sray vb->vb_rows[r] = &vb->vb_buffer[r * 387256145Sray vb->vb_scr_size.tp_col]; 388256145Sray} 389256145Sray 390219888Sedvoid 391219888Sedvtbuf_init_early(struct vt_buf *vb) 392219888Sed{ 393219888Sed 394219888Sed vb->vb_flags |= VBF_CURSOR; 395256145Sray vb->vb_roffset = 0; 396256145Sray vb->vb_curroffset = 0; 397258090Sray vb->vb_mark_start.tp_row = 0; 398258090Sray vb->vb_mark_start.tp_col = 0; 399258090Sray vb->vb_mark_end.tp_row = 0; 400258090Sray vb->vb_mark_end.tp_col = 0; 401256145Sray 402256145Sray vtbuf_init_rows(vb); 403219888Sed vtbuf_make_undirty(vb); 404256145Sray if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 405256145Sray mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 406256145Sray vb->vb_flags |= VBF_MTX_INIT; 407256145Sray } 408219888Sed} 409219888Sed 410219888Sedvoid 411219888Sedvtbuf_init(struct vt_buf *vb, const term_pos_t *p) 412219888Sed{ 413256145Sray int sz; 414219888Sed 415256145Sray vb->vb_scr_size = *p; 416256145Sray vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 417256145Sray 418256145Sray if ((vb->vb_flags & VBF_STATIC) == 0) { 419256145Sray sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 420256894Sray vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 421256145Sray 422256145Sray sz = vb->vb_history_size * sizeof(term_char_t *); 423256894Sray vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 424256145Sray } 425256145Sray 426219888Sed vtbuf_init_early(vb); 427219888Sed} 428219888Sed 429219888Sedvoid 430256145Srayvtbuf_sethistory_size(struct vt_buf *vb, int size) 431219888Sed{ 432256145Sray term_pos_t p; 433219888Sed 434256145Sray /* With same size */ 435256145Sray p.tp_row = vb->vb_scr_size.tp_row; 436256145Sray p.tp_col = vb->vb_scr_size.tp_col; 437256145Sray vtbuf_grow(vb, &p, size); 438256145Sray} 439256145Sray 440256145Srayvoid 441256145Srayvtbuf_grow(struct vt_buf *vb, const term_pos_t *p, int history_size) 442256145Sray{ 443256145Sray term_char_t *old, *new, **rows, **oldrows, **copyrows, *row; 444256145Sray int bufsize, rowssize, w, h, c, r; 445256145Sray term_rect_t rect; 446256145Sray 447256145Sray history_size = MAX(history_size, p->tp_row); 448256145Sray 449256145Sray if (history_size > vb->vb_history_size || p->tp_col > 450256145Sray vb->vb_scr_size.tp_col) { 451219888Sed /* Allocate new buffer. */ 452256145Sray bufsize = history_size * p->tp_col * sizeof(term_char_t); 453256894Sray new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 454256145Sray rowssize = history_size * sizeof(term_pos_t *); 455256894Sray rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 456219888Sed 457219888Sed /* Toggle it. */ 458219888Sed VTBUF_LOCK(vb); 459219888Sed old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 460256145Sray oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 461256145Sray copyrows = vb->vb_rows; 462256145Sray w = vb->vb_scr_size.tp_col; 463256145Sray h = vb->vb_history_size; 464256145Sray 465256145Sray vb->vb_history_size = history_size; 466219888Sed vb->vb_buffer = new; 467256145Sray vb->vb_rows = rows; 468219888Sed vb->vb_flags &= ~VBF_STATIC; 469256145Sray vb->vb_scr_size = *p; 470256145Sray vtbuf_init_rows(vb); 471256145Sray 472256145Sray /* Copy history and fill extra space. */ 473256145Sray for (r = 0; r < history_size; r ++) { 474256145Sray row = rows[r]; 475256145Sray if (r < h) { /* Copy. */ 476256145Sray memmove(rows[r], copyrows[r], 477256145Sray MIN(p->tp_col, w) * sizeof(term_char_t)); 478256145Sray for (c = MIN(p->tp_col, w); c < p->tp_col; 479256145Sray c++) { 480256145Sray row[c] = VTBUF_SPACE_CHAR; 481256145Sray } 482256145Sray } else { /* Just fill. */ 483256145Sray rect.tr_begin.tp_col = 0; 484256145Sray rect.tr_begin.tp_row = r; 485256145Sray rect.tr_end.tp_col = p->tp_col; 486256145Sray rect.tr_end.tp_row = p->tp_row; 487256145Sray vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR); 488256145Sray break; 489256145Sray } 490256145Sray } 491219888Sed vtbuf_make_undirty(vb); 492219888Sed VTBUF_UNLOCK(vb); 493219888Sed /* Deallocate old buffer. */ 494256145Sray free(old, M_VTBUF); 495256145Sray free(oldrows, M_VTBUF); 496219888Sed } 497219888Sed} 498219888Sed 499219888Sedvoid 500219888Sedvtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 501219888Sed{ 502256145Sray term_char_t *row; 503219888Sed 504256145Sray KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 505256145Sray ("vtbuf_putchar tp_row %d must be less than screen width %d", 506256145Sray p->tp_row, vb->vb_scr_size.tp_row)); 507256145Sray KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 508256145Sray ("vtbuf_putchar tp_col %d must be less than screen height %d", 509256145Sray p->tp_col, vb->vb_scr_size.tp_col)); 510256145Sray 511256145Sray row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 512256145Sray VTBUF_MAX_HEIGHT(vb)]; 513256145Sray if (row[p->tp_col] != c) { 514256145Sray VTBUF_LOCK(vb); 515256145Sray row[p->tp_col] = c; 516256145Sray VTBUF_UNLOCK(vb); 517219888Sed vtbuf_dirty_cell(vb, p); 518219888Sed } 519219888Sed} 520219888Sed 521219888Sedvoid 522219888Sedvtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 523219888Sed{ 524219888Sed 525219888Sed if (vb->vb_flags & VBF_CURSOR) { 526219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 527219888Sed vb->vb_cursor = *p; 528219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 529219888Sed } else { 530219888Sed vb->vb_cursor = *p; 531219888Sed } 532219888Sed} 533219888Sed 534219888Sedvoid 535257971Srayvtbuf_mouse_cursor_position(struct vt_buf *vb, int col, int row) 536257971Sray{ 537257971Sray term_rect_t area; 538257971Sray 539257971Sray area.tr_begin.tp_row = MAX(row - 1, 0); 540257971Sray area.tr_begin.tp_col = MAX(col - 1, 0); 541257971Sray area.tr_end.tp_row = MIN(row + 2, vb->vb_scr_size.tp_row); 542257971Sray area.tr_end.tp_col = MIN(col + 2, vb->vb_scr_size.tp_col); 543257971Sray vtbuf_dirty(vb, &area); 544257971Sray} 545257971Sray 546258090Sraystatic void 547258090Srayvtbuf_flush_mark(struct vt_buf *vb) 548258090Sray{ 549258090Sray term_rect_t area; 550258090Sray int s, e; 551258090Sray 552258090Sray /* Notify renderer to update marked region. */ 553258090Sray if (vb->vb_mark_start.tp_col || vb->vb_mark_end.tp_col || 554258090Sray vb->vb_mark_start.tp_row || vb->vb_mark_end.tp_row) { 555258090Sray 556258090Sray s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 557258090Sray e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 558258090Sray 559258090Sray area.tr_begin.tp_col = 0; 560258090Sray area.tr_begin.tp_row = MIN(s, e); 561258090Sray 562258090Sray area.tr_end.tp_col = vb->vb_scr_size.tp_col; 563258090Sray area.tr_end.tp_row = MAX(s, e) + 1; 564258090Sray 565258090Sray vtbuf_dirty(vb, &area); 566258090Sray } 567258090Sray} 568258090Sray 569258090Srayint 570258090Srayvtbuf_get_marked_len(struct vt_buf *vb) 571258090Sray{ 572258090Sray int ei, si, sz; 573258090Sray term_pos_t s, e; 574258090Sray 575258090Sray /* Swap according to window coordinates. */ 576258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 577258134Sray vb->vb_mark_start.tp_col) > 578258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 579258134Sray vb->vb_mark_end.tp_col)) { 580258090Sray POS_COPY(e, vb->vb_mark_start); 581258090Sray POS_COPY(s, vb->vb_mark_end); 582258090Sray } else { 583258090Sray POS_COPY(s, vb->vb_mark_start); 584258090Sray POS_COPY(e, vb->vb_mark_end); 585258090Sray } 586258090Sray 587258090Sray si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 588258090Sray ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 589258090Sray 590258090Sray /* Number symbols and number of rows to inject \n */ 591258090Sray sz = ei - si + ((e.tp_row - s.tp_row) * 2) + 1; 592258090Sray 593258090Sray return (sz * sizeof(term_char_t)); 594258090Sray} 595258090Sray 596257971Srayvoid 597258090Srayvtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 598258090Sray{ 599258090Sray int i, r, c, cs, ce; 600258090Sray term_pos_t s, e; 601258090Sray 602258090Sray /* Swap according to window coordinates. */ 603258134Sray if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), 604258134Sray vb->vb_mark_start.tp_col) > 605258134Sray POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), 606258134Sray vb->vb_mark_end.tp_col)) { 607258090Sray POS_COPY(e, vb->vb_mark_start); 608258090Sray POS_COPY(s, vb->vb_mark_end); 609258090Sray } else { 610258090Sray POS_COPY(s, vb->vb_mark_start); 611258090Sray POS_COPY(e, vb->vb_mark_end); 612258090Sray } 613258090Sray 614258090Sray i = 0; 615258090Sray for (r = s.tp_row; r <= e.tp_row; r ++) { 616258090Sray cs = (r == s.tp_row)?s.tp_col:0; 617258090Sray ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 618258090Sray for (c = cs; c < ce; c ++) { 619258090Sray buf[i++] = vb->vb_rows[r][c]; 620258090Sray } 621258093Sray /* Add new line for all rows, but not for last one. */ 622258093Sray if (r != e.tp_row) { 623258093Sray buf[i++] = '\r'; 624258093Sray buf[i++] = '\n'; 625258093Sray } 626258090Sray } 627258090Sray} 628258090Sray 629258090Srayint 630257971Srayvtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 631257971Sray{ 632258136Sray term_char_t *r; 633258136Sray int i; 634257971Sray 635257971Sray switch (type) { 636258130Sray case VTB_MARK_END: /* B1 UP */ 637258130Sray if (vb->vb_mark_last != VTB_MARK_MOVE) 638258130Sray return (0); 639258130Sray /* FALLTHROUGH */ 640258130Sray case VTB_MARK_MOVE: 641257971Sray case VTB_MARK_EXTEND: 642258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 643257971Sray vb->vb_mark_end.tp_col = col; 644258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 645257971Sray break; 646257971Sray case VTB_MARK_START: 647258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 648257971Sray vb->vb_mark_start.tp_col = col; 649258090Sray vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 650257971Sray /* Start again, so clear end point. */ 651258090Sray vb->vb_mark_end.tp_col = col; 652258090Sray vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 653257971Sray break; 654257971Sray case VTB_MARK_WORD: 655258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 656258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 657258090Sray vtbuf_wth(vb, row); 658258136Sray r = vb->vb_rows[vb->vb_mark_start.tp_row]; 659258136Sray for (i = col; i >= 0; i --) { 660258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 661258136Sray vb->vb_mark_start.tp_col = i + 1; 662258136Sray break; 663258136Sray } 664258136Sray } 665258136Sray for (i = col; i < vb->vb_scr_size.tp_col; i ++) { 666258136Sray if (TCHAR_CHARACTER(r[i]) == ' ') { 667258136Sray vb->vb_mark_end.tp_col = i; 668258136Sray break; 669258136Sray } 670258136Sray } 671258136Sray if (vb->vb_mark_start.tp_col > vb->vb_mark_end.tp_col) 672258136Sray vb->vb_mark_start.tp_col = vb->vb_mark_end.tp_col; 673257971Sray break; 674257971Sray case VTB_MARK_ROW: 675258090Sray vtbuf_flush_mark(vb); /* Clean old mark. */ 676257971Sray vb->vb_mark_start.tp_col = 0; 677257971Sray vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 678258090Sray vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 679258090Sray vtbuf_wth(vb, row); 680257971Sray break; 681258090Sray case VTB_MARK_NONE: 682258130Sray vb->vb_mark_last = type; 683258130Sray /* FALLTHROUGH */ 684258090Sray default: 685258090Sray /* panic? */ 686258090Sray return (0); 687257971Sray } 688258111Sray 689258130Sray vb->vb_mark_last = type; 690258111Sray /* Draw new marked region. */ 691258111Sray vtbuf_flush_mark(vb); 692258111Sray return (1); 693257971Sray} 694257971Sray 695257971Srayvoid 696219888Sedvtbuf_cursor_visibility(struct vt_buf *vb, int yes) 697219888Sed{ 698219888Sed int oflags, nflags; 699219888Sed 700219888Sed VTBUF_LOCK(vb); 701219888Sed oflags = vb->vb_flags; 702219888Sed if (yes) 703219888Sed vb->vb_flags |= VBF_CURSOR; 704219888Sed else 705219888Sed vb->vb_flags &= ~VBF_CURSOR; 706219888Sed nflags = vb->vb_flags; 707219888Sed VTBUF_UNLOCK(vb); 708219888Sed 709219888Sed if (oflags != nflags) 710219888Sed vtbuf_dirty_cell(vb, &vb->vb_cursor); 711219888Sed} 712258090Sray 713258090Srayvoid 714258090Srayvtbuf_scroll_mode(struct vt_buf *vb, int yes) 715258090Sray{ 716258090Sray int oflags, nflags; 717258090Sray 718258090Sray VTBUF_LOCK(vb); 719258090Sray oflags = vb->vb_flags; 720258090Sray if (yes) 721258090Sray vb->vb_flags |= VBF_SCROLL; 722258090Sray else 723258090Sray vb->vb_flags &= ~VBF_SCROLL; 724258090Sray nflags = vb->vb_flags; 725258090Sray VTBUF_UNLOCK(vb); 726258090Sray 727258090Sray if (oflags != nflags) 728258090Sray vtbuf_dirty_cell(vb, &vb->vb_cursor); 729258090Sray} 730258090Sray 731