vt_buf.c revision 258130
1/*- 2 * Copyright (c) 2009, 2013 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Ed Schouten under sponsorship from the 6 * FreeBSD Foundation. 7 * 8 * Portions of this software were developed by Oleksandr Rybalko 9 * under sponsorship from the FreeBSD Foundation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/vt_buf.c 258130 2013-11-14 13:25:47Z ray $"); 35 36#include <sys/param.h> 37#include <sys/kernel.h> 38#include <sys/lock.h> 39#include <sys/malloc.h> 40#include <sys/mutex.h> 41#include <sys/systm.h> 42 43#include <dev/vt/vt.h> 44 45static MALLOC_DEFINE(M_VTBUF, "vtbuf", "vt buffer"); 46 47#define VTBUF_LOCK(vb) mtx_lock_spin(&(vb)->vb_lock) 48#define VTBUF_UNLOCK(vb) mtx_unlock_spin(&(vb)->vb_lock) 49 50#define POS_INDEX(c, r) (((r) << 12) + (c)) 51#define POS_COPY(d, s) do { \ 52 (d).tp_col = (s).tp_col; \ 53 (d).tp_row = (s).tp_row; \ 54} while (0) 55 56 57/* 58 * line4 59 * line5 <--- curroffset (terminal output to that line) 60 * line0 61 * line1 <--- roffset (history display from that point) 62 * line2 63 * line3 64 */ 65int 66vthistory_seek(struct vt_buf *vb, int offset, int whence) 67{ 68 int diff, top, bottom, roffset; 69 70 /* No scrolling if not enabled. */ 71 if ((vb->vb_flags & VBF_SCROLL) == 0) { 72 if (vb->vb_roffset != vb->vb_curroffset) { 73 vb->vb_roffset = vb->vb_curroffset; 74 return (0xffff); 75 } 76 return (0); /* No changes */ 77 } 78 top = (vb->vb_flags & VBF_HISTORY_FULL)? 79 (vb->vb_curroffset + vb->vb_scr_size.tp_row):vb->vb_history_size; 80 bottom = vb->vb_curroffset + vb->vb_history_size; 81 82 /* 83 * Operate on copy of offset value, since it temporary can be bigger 84 * than amount of rows in buffer. 85 */ 86 roffset = vb->vb_roffset + vb->vb_history_size; 87 switch (whence) { 88 case VHS_SET: 89 roffset = offset + vb->vb_history_size; 90 break; 91 case VHS_CUR: 92 roffset += offset; 93 break; 94 case VHS_END: 95 /* Go to current offset. */ 96 roffset = vb->vb_curroffset + vb->vb_history_size; 97 break; 98 } 99 100 roffset = (roffset < top)?top:roffset; 101 roffset = (roffset > bottom)?bottom:roffset; 102 103 roffset %= vb->vb_history_size; 104 105 if (vb->vb_roffset != roffset) { 106 diff = vb->vb_roffset - roffset; 107 vb->vb_roffset = roffset; 108 /* 109 * Offset changed, please update Nth lines on sceen. 110 * +N - Nth lines at top; 111 * -N - Nth lines at bottom. 112 */ 113 return (diff); 114 } 115 return (0); /* No changes */ 116} 117 118void 119vthistory_addlines(struct vt_buf *vb, int offset) 120{ 121 122 vb->vb_curroffset += offset; 123 if (vb->vb_curroffset < 0) 124 vb->vb_curroffset = 0; 125 vb->vb_curroffset %= vb->vb_history_size; 126 if ((vb->vb_flags & VBF_SCROLL) == 0) { 127 vb->vb_roffset = vb->vb_curroffset; 128 } 129} 130 131void 132vthistory_getpos(const struct vt_buf *vb, unsigned int *offset) 133{ 134 135 *offset = vb->vb_roffset; 136} 137 138/* Translate current view row number to history row. */ 139static int 140vtbuf_wth(struct vt_buf *vb, int row) 141{ 142 143 return ((vb->vb_roffset + row) % vb->vb_history_size); 144} 145 146/* Translate history row to current view row number. */ 147static int 148vtbuf_htw(struct vt_buf *vb, int row) 149{ 150 151 /* 152 * total 1000 rows. 153 * History offset roffset winrow 154 * 205 200 ((205 - 200 + 1000) % 1000) = 5 155 * 90 990 ((90 - 990 + 1000) % 1000) = 100 156 */ 157 return ((row - vb->vb_roffset + vb->vb_history_size) % 158 vb->vb_history_size); 159} 160 161int 162vtbuf_iscursor(struct vt_buf *vb, int row, int col) 163{ 164 int sc, sr, ec, er, tmp; 165 166 if ((vb->vb_flags & (VBF_CURSOR|VBF_SCROLL)) == VBF_CURSOR && 167 (vb->vb_cursor.tp_row == row) && (vb->vb_cursor.tp_col == col)) 168 return (1); 169 170 /* Mark cut/paste region. */ 171 172 /* 173 * Luckily screen view is not like circular buffer, so we will 174 * calculate in screen coordinates. Translate first. 175 */ 176 sc = vb->vb_mark_start.tp_col; 177 sr = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 178 ec = vb->vb_mark_end.tp_col; 179 er = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 180 181 182 /* Swap start and end if start > end. */ 183 if (POS_INDEX(sc, sr) > POS_INDEX(ec, er)) { 184 tmp = sc; sc = ec; ec = tmp; 185 tmp = sr; sr = er; er = tmp; 186 } 187 188 if ((POS_INDEX(sc, sr) <= POS_INDEX(col, row)) && 189 (POS_INDEX(col, row) < POS_INDEX(ec, er))) 190 return (1); 191 192 return (0); 193} 194 195static inline uint64_t 196vtbuf_dirty_axis(unsigned int begin, unsigned int end) 197{ 198 uint64_t left, right, mask; 199 200 /* 201 * Mark all bits between begin % 64 and end % 64 dirty. 202 * This code is functionally equivalent to: 203 * 204 * for (i = begin; i < end; i++) 205 * mask |= (uint64_t)1 << (i % 64); 206 */ 207 208 /* Obvious case. Mark everything dirty. */ 209 if (end - begin >= 64) 210 return (VBM_DIRTY); 211 212 /* 1....0; used bits on the left. */ 213 left = VBM_DIRTY << begin % 64; 214 /* 0....1; used bits on the right. */ 215 right = VBM_DIRTY >> -end % 64; 216 217 /* 218 * Only take the intersection. If the result of that is 0, it 219 * means that the selection crossed a 64 bit boundary along the 220 * way, which means we have to take the complement. 221 */ 222 mask = left & right; 223 if (mask == 0) 224 mask = left | right; 225 return (mask); 226} 227 228static inline void 229vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area) 230{ 231 232 VTBUF_LOCK(vb); 233 if (vb->vb_dirtyrect.tr_begin.tp_row > area->tr_begin.tp_row) 234 vb->vb_dirtyrect.tr_begin.tp_row = area->tr_begin.tp_row; 235 if (vb->vb_dirtyrect.tr_begin.tp_col > area->tr_begin.tp_col) 236 vb->vb_dirtyrect.tr_begin.tp_col = area->tr_begin.tp_col; 237 if (vb->vb_dirtyrect.tr_end.tp_row < area->tr_end.tp_row) 238 vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row; 239 if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col) 240 vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col; 241 vb->vb_dirtymask.vbm_row |= 242 vtbuf_dirty_axis(area->tr_begin.tp_row, area->tr_end.tp_row); 243 vb->vb_dirtymask.vbm_col |= 244 vtbuf_dirty_axis(area->tr_begin.tp_col, area->tr_end.tp_col); 245 VTBUF_UNLOCK(vb); 246} 247 248static inline void 249vtbuf_dirty_cell(struct vt_buf *vb, const term_pos_t *p) 250{ 251 term_rect_t area; 252 253 area.tr_begin = *p; 254 area.tr_end.tp_row = p->tp_row + 1; 255 area.tr_end.tp_col = p->tp_col + 1; 256 vtbuf_dirty(vb, &area); 257} 258 259static void 260vtbuf_make_undirty(struct vt_buf *vb) 261{ 262 263 vb->vb_dirtyrect.tr_begin = vb->vb_scr_size; 264 vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0; 265 vb->vb_dirtymask.vbm_row = vb->vb_dirtymask.vbm_col = 0; 266} 267 268void 269vtbuf_undirty(struct vt_buf *vb, term_rect_t *r, struct vt_bufmask *m) 270{ 271 272 VTBUF_LOCK(vb); 273 *r = vb->vb_dirtyrect; 274 *m = vb->vb_dirtymask; 275 vtbuf_make_undirty(vb); 276 VTBUF_UNLOCK(vb); 277} 278 279void 280vtbuf_copy(struct vt_buf *vb, const term_rect_t *r, const term_pos_t *p2) 281{ 282 const term_pos_t *p1 = &r->tr_begin; 283 term_rect_t area; 284 unsigned int rows, cols; 285 int pr, rdiff; 286 287 KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 288 ("vtbuf_copy begin.tp_row %d must be less than screen width %d", 289 r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 290 KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 291 ("vtbuf_copy begin.tp_col %d must be less than screen height %d", 292 r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 293 294 KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 295 ("vtbuf_copy end.tp_row %d must be less than screen width %d", 296 r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 297 KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 298 ("vtbuf_copy end.tp_col %d must be less than screen height %d", 299 r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 300 301 KASSERT(p2->tp_row < vb->vb_scr_size.tp_row, 302 ("vtbuf_copy tp_row %d must be less than screen width %d", 303 p2->tp_row, vb->vb_scr_size.tp_row)); 304 KASSERT(p2->tp_col < vb->vb_scr_size.tp_col, 305 ("vtbuf_copy tp_col %d must be less than screen height %d", 306 p2->tp_col, vb->vb_scr_size.tp_col)); 307 308 rows = r->tr_end.tp_row - r->tr_begin.tp_row; 309 rdiff = r->tr_begin.tp_row - p2->tp_row; 310 cols = r->tr_end.tp_col - r->tr_begin.tp_col; 311 if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 && 312 r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */ 313 (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */ 314 rdiff > 0) { /* Only forward dirrection. Do not eat history. */ 315 vthistory_addlines(vb, rdiff); 316 } else if (p2->tp_row < p1->tp_row) { 317 /* Handle overlapping copies of line segments. */ 318 /* Move data up. */ 319 for (pr = 0; pr < rows; pr++) 320 memmove( 321 &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 322 &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 323 cols * sizeof(term_char_t)); 324 } else { 325 /* Move data down. */ 326 for (pr = rows - 1; pr >= 0; pr--) 327 memmove( 328 &VTBUF_FIELD(vb, p2->tp_row + pr, p2->tp_col), 329 &VTBUF_FIELD(vb, p1->tp_row + pr, p1->tp_col), 330 cols * sizeof(term_char_t)); 331 } 332 333 area.tr_begin = *p2; 334 area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row); 335 area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col); 336 vtbuf_dirty(vb, &area); 337} 338 339static void 340vtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 341{ 342 unsigned int pr, pc; 343 term_char_t *row; 344 345 for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) { 346 row = vb->vb_rows[(vb->vb_curroffset + pr) % 347 VTBUF_MAX_HEIGHT(vb)]; 348 for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) { 349 row[pc] = c; 350 } 351 } 352} 353 354void 355vtbuf_fill_locked(struct vt_buf *vb, const term_rect_t *r, term_char_t c) 356{ 357 KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row, 358 ("vtbuf_fill_locked begin.tp_row %d must be < screen width %d", 359 r->tr_begin.tp_row, vb->vb_scr_size.tp_row)); 360 KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col, 361 ("vtbuf_fill_locked begin.tp_col %d must be < screen height %d", 362 r->tr_begin.tp_col, vb->vb_scr_size.tp_col)); 363 364 KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row, 365 ("vtbuf_fill_locked end.tp_row %d must be <= screen width %d", 366 r->tr_end.tp_row, vb->vb_scr_size.tp_row)); 367 KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col, 368 ("vtbuf_fill_locked end.tp_col %d must be <= screen height %d", 369 r->tr_end.tp_col, vb->vb_scr_size.tp_col)); 370 371 VTBUF_LOCK(vb); 372 vtbuf_fill(vb, r, c); 373 VTBUF_UNLOCK(vb); 374 375 vtbuf_dirty(vb, r); 376} 377 378static void 379vtbuf_init_rows(struct vt_buf *vb) 380{ 381 int r; 382 383 vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row); 384 385 for (r = 0; r < vb->vb_history_size; r++) 386 vb->vb_rows[r] = &vb->vb_buffer[r * 387 vb->vb_scr_size.tp_col]; 388} 389 390void 391vtbuf_init_early(struct vt_buf *vb) 392{ 393 394 vb->vb_flags |= VBF_CURSOR; 395 vb->vb_roffset = 0; 396 vb->vb_curroffset = 0; 397 vb->vb_mark_start.tp_row = 0; 398 vb->vb_mark_start.tp_col = 0; 399 vb->vb_mark_end.tp_row = 0; 400 vb->vb_mark_end.tp_col = 0; 401 402 vtbuf_init_rows(vb); 403 vtbuf_make_undirty(vb); 404 if ((vb->vb_flags & VBF_MTX_INIT) == 0) { 405 mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN); 406 vb->vb_flags |= VBF_MTX_INIT; 407 } 408} 409 410void 411vtbuf_init(struct vt_buf *vb, const term_pos_t *p) 412{ 413 int sz; 414 415 vb->vb_scr_size = *p; 416 vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE; 417 418 if ((vb->vb_flags & VBF_STATIC) == 0) { 419 sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t); 420 vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 421 422 sz = vb->vb_history_size * sizeof(term_char_t *); 423 vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK | M_ZERO); 424 } 425 426 vtbuf_init_early(vb); 427} 428 429void 430vtbuf_sethistory_size(struct vt_buf *vb, int size) 431{ 432 term_pos_t p; 433 434 /* With same size */ 435 p.tp_row = vb->vb_scr_size.tp_row; 436 p.tp_col = vb->vb_scr_size.tp_col; 437 vtbuf_grow(vb, &p, size); 438} 439 440void 441vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, int history_size) 442{ 443 term_char_t *old, *new, **rows, **oldrows, **copyrows, *row; 444 int bufsize, rowssize, w, h, c, r; 445 term_rect_t rect; 446 447 history_size = MAX(history_size, p->tp_row); 448 449 if (history_size > vb->vb_history_size || p->tp_col > 450 vb->vb_scr_size.tp_col) { 451 /* Allocate new buffer. */ 452 bufsize = history_size * p->tp_col * sizeof(term_char_t); 453 new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO); 454 rowssize = history_size * sizeof(term_pos_t *); 455 rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO); 456 457 /* Toggle it. */ 458 VTBUF_LOCK(vb); 459 old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer; 460 oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows; 461 copyrows = vb->vb_rows; 462 w = vb->vb_scr_size.tp_col; 463 h = vb->vb_history_size; 464 465 vb->vb_history_size = history_size; 466 vb->vb_buffer = new; 467 vb->vb_rows = rows; 468 vb->vb_flags &= ~VBF_STATIC; 469 vb->vb_scr_size = *p; 470 vtbuf_init_rows(vb); 471 472 /* Copy history and fill extra space. */ 473 for (r = 0; r < history_size; r ++) { 474 row = rows[r]; 475 if (r < h) { /* Copy. */ 476 memmove(rows[r], copyrows[r], 477 MIN(p->tp_col, w) * sizeof(term_char_t)); 478 for (c = MIN(p->tp_col, w); c < p->tp_col; 479 c++) { 480 row[c] = VTBUF_SPACE_CHAR; 481 } 482 } else { /* Just fill. */ 483 rect.tr_begin.tp_col = 0; 484 rect.tr_begin.tp_row = r; 485 rect.tr_end.tp_col = p->tp_col; 486 rect.tr_end.tp_row = p->tp_row; 487 vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR); 488 break; 489 } 490 } 491 vtbuf_make_undirty(vb); 492 VTBUF_UNLOCK(vb); 493 /* Deallocate old buffer. */ 494 free(old, M_VTBUF); 495 free(oldrows, M_VTBUF); 496 } 497} 498 499void 500vtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c) 501{ 502 term_char_t *row; 503 504 KASSERT(p->tp_row < vb->vb_scr_size.tp_row, 505 ("vtbuf_putchar tp_row %d must be less than screen width %d", 506 p->tp_row, vb->vb_scr_size.tp_row)); 507 KASSERT(p->tp_col < vb->vb_scr_size.tp_col, 508 ("vtbuf_putchar tp_col %d must be less than screen height %d", 509 p->tp_col, vb->vb_scr_size.tp_col)); 510 511 row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) % 512 VTBUF_MAX_HEIGHT(vb)]; 513 if (row[p->tp_col] != c) { 514 VTBUF_LOCK(vb); 515 row[p->tp_col] = c; 516 VTBUF_UNLOCK(vb); 517 vtbuf_dirty_cell(vb, p); 518 } 519} 520 521void 522vtbuf_cursor_position(struct vt_buf *vb, const term_pos_t *p) 523{ 524 525 if (vb->vb_flags & VBF_CURSOR) { 526 vtbuf_dirty_cell(vb, &vb->vb_cursor); 527 vb->vb_cursor = *p; 528 vtbuf_dirty_cell(vb, &vb->vb_cursor); 529 } else { 530 vb->vb_cursor = *p; 531 } 532} 533 534void 535vtbuf_mouse_cursor_position(struct vt_buf *vb, int col, int row) 536{ 537 term_rect_t area; 538 539 area.tr_begin.tp_row = MAX(row - 1, 0); 540 area.tr_begin.tp_col = MAX(col - 1, 0); 541 area.tr_end.tp_row = MIN(row + 2, vb->vb_scr_size.tp_row); 542 area.tr_end.tp_col = MIN(col + 2, vb->vb_scr_size.tp_col); 543 vtbuf_dirty(vb, &area); 544} 545 546static void 547vtbuf_flush_mark(struct vt_buf *vb) 548{ 549 term_rect_t area; 550 int s, e; 551 552 /* Notify renderer to update marked region. */ 553 if (vb->vb_mark_start.tp_col || vb->vb_mark_end.tp_col || 554 vb->vb_mark_start.tp_row || vb->vb_mark_end.tp_row) { 555 556 s = vtbuf_htw(vb, vb->vb_mark_start.tp_row); 557 e = vtbuf_htw(vb, vb->vb_mark_end.tp_row); 558 559 area.tr_begin.tp_col = 0; 560 area.tr_begin.tp_row = MIN(s, e); 561 562 area.tr_end.tp_col = vb->vb_scr_size.tp_col; 563 area.tr_end.tp_row = MAX(s, e) + 1; 564 565 vtbuf_dirty(vb, &area); 566 } 567} 568 569int 570vtbuf_get_marked_len(struct vt_buf *vb) 571{ 572 int ei, si, sz; 573 term_pos_t s, e; 574 575 /* Swap according to window coordinates. */ 576 if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), vb->vb_mark_start.tp_col) > 577 POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), vb->vb_mark_end.tp_col)) { 578 POS_COPY(e, vb->vb_mark_start); 579 POS_COPY(s, vb->vb_mark_end); 580 } else { 581 POS_COPY(s, vb->vb_mark_start); 582 POS_COPY(e, vb->vb_mark_end); 583 } 584 585 si = s.tp_row * vb->vb_scr_size.tp_col + s.tp_col; 586 ei = e.tp_row * vb->vb_scr_size.tp_col + e.tp_col; 587 588 /* Number symbols and number of rows to inject \n */ 589 sz = ei - si + ((e.tp_row - s.tp_row) * 2) + 1; 590 591 return (sz * sizeof(term_char_t)); 592} 593 594void 595vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz) 596{ 597 int i, r, c, cs, ce; 598 term_pos_t s, e; 599 600 /* Swap according to window coordinates. */ 601 if (POS_INDEX(vtbuf_htw(vb, vb->vb_mark_start.tp_row), vb->vb_mark_start.tp_col) > 602 POS_INDEX(vtbuf_htw(vb, vb->vb_mark_end.tp_row), vb->vb_mark_end.tp_col)) { 603 POS_COPY(e, vb->vb_mark_start); 604 POS_COPY(s, vb->vb_mark_end); 605 } else { 606 POS_COPY(s, vb->vb_mark_start); 607 POS_COPY(e, vb->vb_mark_end); 608 } 609 610 i = 0; 611 for (r = s.tp_row; r <= e.tp_row; r ++) { 612 cs = (r == s.tp_row)?s.tp_col:0; 613 ce = (r == e.tp_row)?e.tp_col:vb->vb_scr_size.tp_col; 614 for (c = cs; c < ce; c ++) { 615 buf[i++] = vb->vb_rows[r][c]; 616 } 617 /* Add new line for all rows, but not for last one. */ 618 if (r != e.tp_row) { 619 buf[i++] = '\r'; 620 buf[i++] = '\n'; 621 } 622 } 623} 624 625int 626vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row) 627{ 628 629 switch (type) { 630 case VTB_MARK_END: /* B1 UP */ 631 if (vb->vb_mark_last != VTB_MARK_MOVE) 632 return (0); 633 /* FALLTHROUGH */ 634 case VTB_MARK_MOVE: 635 case VTB_MARK_EXTEND: 636 vtbuf_flush_mark(vb); /* Clean old mark. */ 637 vb->vb_mark_end.tp_col = col; 638 vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 639 break; 640 case VTB_MARK_START: 641 vtbuf_flush_mark(vb); /* Clean old mark. */ 642 vb->vb_mark_start.tp_col = col; 643 vb->vb_mark_start.tp_row = vtbuf_wth(vb, row); 644 /* Start again, so clear end point. */ 645 vb->vb_mark_end.tp_col = col; 646 vb->vb_mark_end.tp_row = vtbuf_wth(vb, row); 647 break; 648 case VTB_MARK_WORD: 649 vtbuf_flush_mark(vb); /* Clean old mark. */ 650 vb->vb_mark_start.tp_col = 0; /* XXX */ 651 vb->vb_mark_end.tp_col = 10; /* XXX */ 652 vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 653 vtbuf_wth(vb, row); 654 break; 655 case VTB_MARK_ROW: 656 vtbuf_flush_mark(vb); /* Clean old mark. */ 657 vb->vb_mark_start.tp_col = 0; 658 vb->vb_mark_end.tp_col = vb->vb_scr_size.tp_col; 659 vb->vb_mark_start.tp_row = vb->vb_mark_end.tp_row = 660 vtbuf_wth(vb, row); 661 break; 662 case VTB_MARK_NONE: 663 vb->vb_mark_last = type; 664 /* FALLTHROUGH */ 665 default: 666 /* panic? */ 667 return (0); 668 } 669 670 vb->vb_mark_last = type; 671 /* Draw new marked region. */ 672 vtbuf_flush_mark(vb); 673 return (1); 674} 675 676void 677vtbuf_cursor_visibility(struct vt_buf *vb, int yes) 678{ 679 int oflags, nflags; 680 681 VTBUF_LOCK(vb); 682 oflags = vb->vb_flags; 683 if (yes) 684 vb->vb_flags |= VBF_CURSOR; 685 else 686 vb->vb_flags &= ~VBF_CURSOR; 687 nflags = vb->vb_flags; 688 VTBUF_UNLOCK(vb); 689 690 if (oflags != nflags) 691 vtbuf_dirty_cell(vb, &vb->vb_cursor); 692} 693 694void 695vtbuf_scroll_mode(struct vt_buf *vb, int yes) 696{ 697 int oflags, nflags; 698 699 VTBUF_LOCK(vb); 700 oflags = vb->vb_flags; 701 if (yes) 702 vb->vb_flags |= VBF_SCROLL; 703 else 704 vb->vb_flags &= ~VBF_SCROLL; 705 nflags = vb->vb_flags; 706 VTBUF_UNLOCK(vb); 707 708 if (oflags != nflags) 709 vtbuf_dirty_cell(vb, &vb->vb_cursor); 710} 711 712