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