Mercurial > vim
comparison src/libvterm/src/screen.c @ 30880:82336c3b679d v9.0.0774
patch 9.0.0774: the libvterm code is outdated
Commit: https://github.com/vim/vim/commit/6a12d26f3404e45ce25cf9152857e355b28f392a
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Oct 16 19:26:52 2022 +0100
patch 9.0.0774: the libvterm code is outdated
Problem: The libvterm code is outdated.
Solution: Include libvterm changes from revision 802 to 817. Revert some
changes made for C89.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 16 Oct 2022 20:30:07 +0200 |
parents | 2d2758ffd959 |
children | ac9464a32606 |
comparison
equal
deleted
inserted
replaced
30879:2db86b9d26df | 30880:82336c3b679d |
---|---|
7 #include "rect.h" | 7 #include "rect.h" |
8 #include "utf8.h" | 8 #include "utf8.h" |
9 | 9 |
10 #define UNICODE_SPACE 0x20 | 10 #define UNICODE_SPACE 0x20 |
11 #define UNICODE_LINEFEED 0x0a | 11 #define UNICODE_LINEFEED 0x0a |
12 | |
13 #undef DEBUG_REFLOW | |
12 | 14 |
13 /* State of the pen at some moment in time, also used in a cell */ | 15 /* State of the pen at some moment in time, also used in a cell */ |
14 typedef struct | 16 typedef struct |
15 { | 17 { |
16 /* After the bitfield */ | 18 /* After the bitfield */ |
22 unsigned int blink : 1; | 24 unsigned int blink : 1; |
23 unsigned int reverse : 1; | 25 unsigned int reverse : 1; |
24 unsigned int conceal : 1; | 26 unsigned int conceal : 1; |
25 unsigned int strike : 1; | 27 unsigned int strike : 1; |
26 unsigned int font : 4; /* 0 to 9 */ | 28 unsigned int font : 4; /* 0 to 9 */ |
29 unsigned int small : 1; | |
30 unsigned int baseline : 2; | |
27 | 31 |
28 /* Extra state storage that isn't strictly pen-related */ | 32 /* Extra state storage that isn't strictly pen-related */ |
29 unsigned int protected_cell : 1; | 33 unsigned int protected_cell : 1; |
30 unsigned int dwl : 1; /* on a DECDWL or DECDHL line */ | 34 unsigned int dwl : 1; /* on a DECDWL or DECDHL line */ |
31 unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */ | 35 unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */ |
52 VTermRect pending_scrollrect; | 56 VTermRect pending_scrollrect; |
53 int pending_scroll_downward, pending_scroll_rightward; | 57 int pending_scroll_downward, pending_scroll_rightward; |
54 | 58 |
55 int rows; | 59 int rows; |
56 int cols; | 60 int cols; |
57 int global_reverse; | 61 |
62 unsigned int global_reverse : 1; | |
63 unsigned int reflow : 1; | |
58 | 64 |
59 /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ | 65 /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ |
60 ScreenCell *buffers[2]; | 66 ScreenCell *buffers[2]; |
61 | 67 |
62 /* buffer will == buffers[0] or buffers[1], depending on altscreen */ | 68 /* buffer will == buffers[0] or buffers[1], depending on altscreen */ |
86 } | 92 } |
87 | 93 |
88 static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) | 94 static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) |
89 { | 95 { |
90 ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); | 96 ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); |
91 int row; | 97 |
92 int col; | 98 for(int row = 0; row < rows; row++) { |
93 | 99 for(int col = 0; col < cols; col++) { |
94 for(row = 0; row < rows; row++) { | |
95 for(col = 0; col < cols; col++) { | |
96 clearcell(screen, &new_buffer[row * cols + col]); | 100 clearcell(screen, &new_buffer[row * cols + col]); |
97 } | 101 } |
98 } | 102 } |
99 | 103 |
100 return new_buffer; | 104 return new_buffer; |
166 damagerect(screen, rect); | 170 damagerect(screen, rect); |
167 } | 171 } |
168 | 172 |
169 static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) | 173 static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) |
170 { | 174 { |
171 int i; | |
172 int col; | |
173 VTermRect rect; | |
174 | |
175 VTermScreen *screen = user; | 175 VTermScreen *screen = user; |
176 ScreenCell *cell = getcell(screen, pos.row, pos.col); | 176 ScreenCell *cell = getcell(screen, pos.row, pos.col); |
177 | 177 |
178 if(!cell) | 178 if(!cell) |
179 return 0; | 179 return 0; |
180 | 180 |
181 int i; | |
181 for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { | 182 for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) { |
182 cell->chars[i] = info->chars[i]; | 183 cell->chars[i] = info->chars[i]; |
183 cell->pen = screen->pen; | 184 cell->pen = screen->pen; |
184 } | 185 } |
185 if(i < VTERM_MAX_CHARS_PER_CELL) | 186 if(i < VTERM_MAX_CHARS_PER_CELL) |
186 cell->chars[i] = 0; | 187 cell->chars[i] = 0; |
187 | 188 |
188 for(col = 1; col < info->width; col++) | 189 for(int col = 1; col < info->width; col++) |
189 { | 190 { |
190 ScreenCell *onecell = getcell(screen, pos.row, pos.col + col); | 191 ScreenCell *onecell = getcell(screen, pos.row, pos.col + col); |
191 if (onecell == NULL) | 192 if (onecell == NULL) |
192 break; | 193 break; |
193 onecell->chars[0] = (uint32_t)-1; | 194 onecell->chars[0] = (uint32_t)-1; |
194 } | 195 } |
195 | 196 |
197 VTermRect rect; | |
196 rect.start_row = pos.row; | 198 rect.start_row = pos.row; |
197 rect.end_row = pos.row+1; | 199 rect.end_row = pos.row+1; |
198 rect.start_col = pos.col; | 200 rect.start_col = pos.col; |
199 rect.end_col = pos.col+info->width; | 201 rect.end_col = pos.col+info->width; |
200 | 202 |
223 | 225 |
224 if(screen->callbacks && screen->callbacks->sb_pushline && | 226 if(screen->callbacks && screen->callbacks->sb_pushline && |
225 dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner | 227 dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner |
226 dest.end_col == screen->cols && // full width | 228 dest.end_col == screen->cols && // full width |
227 screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen | 229 screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen |
228 int row; | 230 for(int row = 0; row < src.start_row; row++) |
229 for(row = 0; row < src.start_row; row++) | |
230 sb_pushline_from_row(screen, row); | 231 sb_pushline_from_row(screen, row); |
231 } | 232 } |
232 | 233 |
233 { | 234 int cols = src.end_col - src.start_col; |
234 int cols = src.end_col - src.start_col; | 235 int downward = src.start_row - dest.start_row; |
235 int downward = src.start_row - dest.start_row; | 236 |
236 int init_row, test_row, inc_row; | 237 int init_row, test_row, inc_row; |
237 int row; | 238 if(downward < 0) { |
238 | 239 init_row = dest.end_row - 1; |
239 if(downward < 0) { | 240 test_row = dest.start_row - 1; |
240 init_row = dest.end_row - 1; | 241 inc_row = -1; |
241 test_row = dest.start_row - 1; | 242 } |
242 inc_row = -1; | 243 else { |
243 } | 244 init_row = dest.start_row; |
244 else { | 245 test_row = dest.end_row; |
245 init_row = dest.start_row; | 246 inc_row = +1; |
246 test_row = dest.end_row; | 247 } |
247 inc_row = +1; | 248 |
248 } | 249 for(int row = init_row; row != test_row; row += inc_row) |
249 | 250 memmove(getcell(screen, row, dest.start_col), |
250 for(row = init_row; row != test_row; row += inc_row) | 251 getcell(screen, row + downward, src.start_col), |
251 memmove(getcell(screen, row, dest.start_col), | 252 cols * sizeof(ScreenCell)); |
252 getcell(screen, row + downward, src.start_col), | |
253 cols * sizeof(ScreenCell)); | |
254 } | |
255 | 253 |
256 return 1; | 254 return 1; |
257 } | 255 } |
258 | 256 |
259 static int moverect_user(VTermRect dest, VTermRect src, void *user) | 257 static int moverect_user(VTermRect dest, VTermRect src, void *user) |
275 } | 273 } |
276 | 274 |
277 static int erase_internal(VTermRect rect, int selective, void *user) | 275 static int erase_internal(VTermRect rect, int selective, void *user) |
278 { | 276 { |
279 VTermScreen *screen = user; | 277 VTermScreen *screen = user; |
280 int row, col; | 278 |
281 | 279 for(int row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) { |
282 for(row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) { | |
283 const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); | 280 const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); |
284 | 281 |
285 for(col = rect.start_col; col < rect.end_col; col++) { | 282 for(int col = rect.start_col; col < rect.end_col; col++) { |
286 ScreenCell *cell = getcell(screen, row, col); | 283 ScreenCell *cell = getcell(screen, row, col); |
287 | 284 |
288 if (cell == NULL) | 285 if (cell == NULL) |
289 { | 286 { |
290 DEBUG_LOG2("libvterm: erase_internal() position invalid: %d / %d", | 287 DEBUG_LOG2("libvterm: erase_internal() position invalid: %d / %d", |
446 screen->pen.fg = val->color; | 443 screen->pen.fg = val->color; |
447 return 1; | 444 return 1; |
448 case VTERM_ATTR_BACKGROUND: | 445 case VTERM_ATTR_BACKGROUND: |
449 screen->pen.bg = val->color; | 446 screen->pen.bg = val->color; |
450 return 1; | 447 return 1; |
448 case VTERM_ATTR_SMALL: | |
449 screen->pen.small = val->boolean; | |
450 return 1; | |
451 case VTERM_ATTR_BASELINE: | |
452 screen->pen.baseline = val->number; | |
453 return 1; | |
451 | 454 |
452 case VTERM_N_ATTRS: | 455 case VTERM_N_ATTRS: |
453 return 0; | 456 return 0; |
454 } | 457 } |
455 | 458 |
494 return (*screen->callbacks->bell)(screen->cbdata); | 497 return (*screen->callbacks->bell)(screen->cbdata); |
495 | 498 |
496 return 0; | 499 return 0; |
497 } | 500 } |
498 | 501 |
502 /* How many cells are non-blank | |
503 * Returns the position of the first blank cell in the trailing blank end */ | |
504 static int line_popcount(ScreenCell *buffer, int row, int rows UNUSED, int cols) | |
505 { | |
506 int col = cols - 1; | |
507 while(col >= 0 && buffer[row * cols + col].chars[0] == 0) | |
508 col--; | |
509 return col + 1; | |
510 } | |
511 | |
512 #define REFLOW (screen->reflow) | |
513 | |
499 static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermStateFields *statefields) | 514 static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermStateFields *statefields) |
500 { | 515 { |
501 int old_rows = screen->rows; | 516 int old_rows = screen->rows; |
502 int old_cols = screen->cols; | 517 int old_cols = screen->cols; |
503 | 518 |
508 VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); | 523 VTermLineInfo *new_lineinfo = vterm_allocator_malloc(screen->vt, sizeof(new_lineinfo[0]) * new_rows); |
509 | 524 |
510 // Find the final row of old buffer content | 525 // Find the final row of old buffer content |
511 int old_row = old_rows - 1; | 526 int old_row = old_rows - 1; |
512 int new_row = new_rows - 1; | 527 int new_row = new_rows - 1; |
513 int col; | 528 |
514 | 529 VTermPos old_cursor = statefields->pos; |
515 while(new_row >= 0 && old_row >= 0) { | 530 VTermPos new_cursor = { -1, -1 }; |
516 for(col = 0; col < old_cols && col < new_cols; col++) | 531 |
517 new_buffer[new_row * new_cols + col] = old_buffer[old_row * old_cols + col]; | 532 #ifdef DEBUG_REFLOW |
518 for( ; col < new_cols; col++) | 533 fprintf(stderr, "Resizing from %dx%d to %dx%d; cursor was at (%d,%d)\n", |
519 clearcell(screen, &new_buffer[new_row * new_cols + col]); | 534 old_cols, old_rows, new_cols, new_rows, old_cursor.col, old_cursor.row); |
520 | 535 #endif |
521 new_lineinfo[new_row] = old_lineinfo[old_row]; | 536 |
522 | 537 /* Keep track of the final row that is knonw to be blank, so we know what |
523 old_row--; | 538 * spare space we have for scrolling into |
524 new_row--; | 539 */ |
525 | 540 int final_blank_row = new_rows; |
526 if(new_row < 0 && old_row >= 0 && | 541 |
527 new_buffer[(new_rows - 1) * new_cols].chars[0] == 0 && | 542 while(old_row >= 0) { |
528 (!active || statefields->pos.row < (new_rows - 1))) { | 543 int old_row_end = old_row; |
529 int moverows = new_rows - 1; | 544 /* TODO: Stop if dwl or dhl */ |
530 memmove(&new_buffer[1 * new_cols], &new_buffer[0], moverows * new_cols * sizeof(ScreenCell)); | 545 while(REFLOW && old_lineinfo && old_row >= 0 && old_lineinfo[old_row].continuation) |
531 | 546 old_row--; |
532 new_row++; | 547 int old_row_start = old_row; |
533 } | 548 |
549 int width = 0; | |
550 for(int row = old_row_start; row <= old_row_end; row++) { | |
551 if(REFLOW && row < (old_rows - 1) && old_lineinfo[row + 1].continuation) | |
552 width += old_cols; | |
553 else | |
554 width += line_popcount(old_buffer, row, old_rows, old_cols); | |
555 } | |
556 | |
557 if(final_blank_row == (new_row + 1) && width == 0) | |
558 final_blank_row = new_row; | |
559 | |
560 int new_height = REFLOW | |
561 ? width ? (width + new_cols - 1) / new_cols : 1 | |
562 : 1; | |
563 | |
564 int new_row_end = new_row; | |
565 int new_row_start = new_row - new_height + 1; | |
566 | |
567 old_row = old_row_start; | |
568 int old_col = 0; | |
569 | |
570 int spare_rows = new_rows - final_blank_row; | |
571 | |
572 if(new_row_start < 0 && /* we'd fall off the top */ | |
573 spare_rows >= 0 && /* we actually have spare rows */ | |
574 (!active || new_cursor.row == -1 || (new_cursor.row - new_row_start) < new_rows)) | |
575 { | |
576 /* Attempt to scroll content down into the blank rows at the bottom to | |
577 * make it fit | |
578 */ | |
579 int downwards = -new_row_start; | |
580 if(downwards > spare_rows) | |
581 downwards = spare_rows; | |
582 int rowcount = new_rows - downwards; | |
583 | |
584 #ifdef DEBUG_REFLOW | |
585 fprintf(stderr, " scroll %d rows +%d downwards\n", rowcount, downwards); | |
586 #endif | |
587 | |
588 memmove(&new_buffer[downwards * new_cols], &new_buffer[0], rowcount * new_cols * sizeof(ScreenCell)); | |
589 memmove(&new_lineinfo[downwards], &new_lineinfo[0], rowcount * sizeof(new_lineinfo[0])); | |
590 | |
591 new_row += downwards; | |
592 new_row_start += downwards; | |
593 new_row_end += downwards; | |
594 | |
595 if(new_cursor.row >= 0) | |
596 new_cursor.row += downwards; | |
597 | |
598 final_blank_row += downwards; | |
599 } | |
600 | |
601 #ifdef DEBUG_REFLOW | |
602 fprintf(stderr, " rows [%d..%d] <- [%d..%d] width=%d\n", | |
603 new_row_start, new_row_end, old_row_start, old_row_end, width); | |
604 #endif | |
605 | |
606 if(new_row_start < 0) | |
607 break; | |
608 | |
609 for(new_row = new_row_start, old_row = old_row_start; new_row <= new_row_end; new_row++) { | |
610 int count = width >= new_cols ? new_cols : width; | |
611 width -= count; | |
612 | |
613 int new_col = 0; | |
614 | |
615 while(count) { | |
616 /* TODO: This could surely be done a lot faster by memcpy()'ing the entire range */ | |
617 new_buffer[new_row * new_cols + new_col] = old_buffer[old_row * old_cols + old_col]; | |
618 | |
619 if(old_cursor.row == old_row && old_cursor.col == old_col) | |
620 new_cursor.row = new_row, new_cursor.col = new_col; | |
621 | |
622 old_col++; | |
623 if(old_col == old_cols) { | |
624 old_row++; | |
625 | |
626 if(!REFLOW) { | |
627 new_col++; | |
628 break; | |
629 } | |
630 old_col = 0; | |
631 } | |
632 | |
633 new_col++; | |
634 count--; | |
635 } | |
636 | |
637 if(old_cursor.row == old_row && old_cursor.col >= old_col) { | |
638 new_cursor.row = new_row, new_cursor.col = (old_cursor.col - old_col + new_col); | |
639 if(new_cursor.col >= new_cols) | |
640 new_cursor.col = new_cols-1; | |
641 } | |
642 | |
643 while(new_col < new_cols) { | |
644 clearcell(screen, &new_buffer[new_row * new_cols + new_col]); | |
645 new_col++; | |
646 } | |
647 | |
648 new_lineinfo[new_row].continuation = (new_row > new_row_start); | |
649 } | |
650 | |
651 old_row = old_row_start - 1; | |
652 new_row = new_row_start - 1; | |
653 } | |
654 | |
655 if(old_cursor.row <= old_row) { | |
656 /* cursor would have moved entirely off the top of the screen; lets just | |
657 * bring it within range */ | |
658 new_cursor.row = 0, new_cursor.col = old_cursor.col; | |
659 if(new_cursor.col >= new_cols) | |
660 new_cursor.col = new_cols-1; | |
661 } | |
662 | |
663 /* We really expect the cursor position to be set by now */ | |
664 if(active && (new_cursor.row == -1 || new_cursor.col == -1)) { | |
665 fprintf(stderr, "screen_resize failed to update cursor position\n"); | |
666 abort(); | |
534 } | 667 } |
535 | 668 |
536 if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { | 669 if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { |
537 /* Push spare lines to scrollback buffer */ | 670 /* Push spare lines to scrollback buffer */ |
538 int row; | 671 for(int row = 0; row <= old_row; row++) |
539 for(row = 0; row <= old_row; row++) | |
540 sb_pushline_from_row(screen, row); | 672 sb_pushline_from_row(screen, row); |
541 if(active) | 673 if(active) |
542 statefields->pos.row -= (old_row + 1); | 674 statefields->pos.row -= (old_row + 1); |
543 } | 675 } |
544 if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && | 676 if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && |
551 | 683 |
552 pos.row = new_row; | 684 pos.row = new_row; |
553 for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { | 685 for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { |
554 VTermScreenCell *src = &screen->sb_buffer[pos.col]; | 686 VTermScreenCell *src = &screen->sb_buffer[pos.col]; |
555 ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; | 687 ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; |
556 int i; | 688 |
557 | 689 for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { |
558 for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { | |
559 dst->chars[i] = src->chars[i]; | 690 dst->chars[i] = src->chars[i]; |
560 if(!src->chars[i]) | 691 if(!src->chars[i]) |
561 break; | 692 break; |
562 } | 693 } |
563 | 694 |
567 dst->pen.blink = src->attrs.blink; | 698 dst->pen.blink = src->attrs.blink; |
568 dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; | 699 dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; |
569 dst->pen.conceal = src->attrs.conceal; | 700 dst->pen.conceal = src->attrs.conceal; |
570 dst->pen.strike = src->attrs.strike; | 701 dst->pen.strike = src->attrs.strike; |
571 dst->pen.font = src->attrs.font; | 702 dst->pen.font = src->attrs.font; |
703 dst->pen.small = src->attrs.small; | |
704 dst->pen.baseline = src->attrs.baseline; | |
572 | 705 |
573 dst->pen.fg = src->fg; | 706 dst->pen.fg = src->fg; |
574 dst->pen.bg = src->bg; | 707 dst->pen.bg = src->bg; |
575 | 708 |
576 if(src->width == 2 && pos.col < (new_cols-1)) | 709 if(src->width == 2 && pos.col < (new_cols-1)) |
582 | 715 |
583 if(active) | 716 if(active) |
584 statefields->pos.row++; | 717 statefields->pos.row++; |
585 } | 718 } |
586 } | 719 } |
587 | |
588 if(new_row >= 0) { | 720 if(new_row >= 0) { |
589 /* Scroll new rows back up to the top and fill in blanks at the bottom */ | 721 /* Scroll new rows back up to the top and fill in blanks at the bottom */ |
590 int moverows = new_rows - new_row - 1; | 722 int moverows = new_rows - new_row - 1; |
591 memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); | 723 memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); |
592 memmove(&new_lineinfo[0], &new_lineinfo[new_row + 1], moverows * sizeof(new_lineinfo[0])); | 724 memmove(&new_lineinfo[0], &new_lineinfo[new_row + 1], moverows * sizeof(new_lineinfo[0])); |
593 | 725 |
726 new_cursor.row -= (new_row + 1); | |
727 | |
594 for(new_row = moverows; new_row < new_rows; new_row++) { | 728 for(new_row = moverows; new_row < new_rows; new_row++) { |
595 for(col = 0; col < new_cols; col++) | 729 for(int col = 0; col < new_cols; col++) |
596 clearcell(screen, &new_buffer[new_row * new_cols + col]); | 730 clearcell(screen, &new_buffer[new_row * new_cols + col]); |
597 new_lineinfo[new_row] = (VTermLineInfo){ 0 }; | 731 new_lineinfo[new_row] = (VTermLineInfo){ 0 }; |
598 } | 732 } |
599 } | 733 } |
600 | 734 |
602 screen->buffers[bufidx] = new_buffer; | 736 screen->buffers[bufidx] = new_buffer; |
603 | 737 |
604 vterm_allocator_free(screen->vt, old_lineinfo); | 738 vterm_allocator_free(screen->vt, old_lineinfo); |
605 statefields->lineinfos[bufidx] = new_lineinfo; | 739 statefields->lineinfos[bufidx] = new_lineinfo; |
606 | 740 |
741 if(active) | |
742 statefields->pos = new_cursor; | |
743 | |
607 return; | 744 return; |
608 | |
609 /* REFLOW TODO: | |
610 * Handle delta. Probably needs to be a full cursorpos that we edit | |
611 */ | |
612 } | 745 } |
613 | 746 |
614 static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) | 747 static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) |
615 { | 748 { |
616 VTermScreen *screen = user; | 749 VTermScreen *screen = user; |
665 } | 798 } |
666 | 799 |
667 static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) | 800 static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) |
668 { | 801 { |
669 VTermScreen *screen = user; | 802 VTermScreen *screen = user; |
670 int col; | |
671 VTermRect rect; | |
672 | 803 |
673 if(newinfo->doublewidth != oldinfo->doublewidth || | 804 if(newinfo->doublewidth != oldinfo->doublewidth || |
674 newinfo->doubleheight != oldinfo->doubleheight) { | 805 newinfo->doubleheight != oldinfo->doubleheight) { |
675 for(col = 0; col < screen->cols; col++) { | 806 for(int col = 0; col < screen->cols; col++) { |
676 ScreenCell *cell = getcell(screen, row, col); | 807 ScreenCell *cell = getcell(screen, row, col); |
677 if (cell == NULL) | 808 if (cell == NULL) |
678 { | 809 { |
679 DEBUG_LOG2("libvterm: setlineinfo() position invalid: %d / %d", | 810 DEBUG_LOG2("libvterm: setlineinfo() position invalid: %d / %d", |
680 row, col); | 811 row, col); |
682 } | 813 } |
683 cell->pen.dwl = newinfo->doublewidth; | 814 cell->pen.dwl = newinfo->doublewidth; |
684 cell->pen.dhl = newinfo->doubleheight; | 815 cell->pen.dhl = newinfo->doubleheight; |
685 } | 816 } |
686 | 817 |
818 VTermRect rect; | |
687 rect.start_row = row; | 819 rect.start_row = row; |
688 rect.end_row = row + 1; | 820 rect.end_row = row + 1; |
689 rect.start_col = 0; | 821 rect.start_col = 0; |
690 rect.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols; | 822 rect.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols; |
691 damagerect(screen, rect); | 823 damagerect(screen, rect); |
697 erase_internal(rect, 0, user); | 829 erase_internal(rect, 0, user); |
698 } | 830 } |
699 } | 831 } |
700 | 832 |
701 return 1; | 833 return 1; |
834 } | |
835 | |
836 static int sb_clear(void *user) { | |
837 VTermScreen *screen = user; | |
838 | |
839 if(screen->callbacks && screen->callbacks->sb_clear) | |
840 if((*screen->callbacks->sb_clear)(screen->cbdata)) | |
841 return 1; | |
842 | |
843 return 0; | |
702 } | 844 } |
703 | 845 |
704 static VTermStateCallbacks state_cbs = { | 846 static VTermStateCallbacks state_cbs = { |
705 &putglyph, // putglyph | 847 &putglyph, // putglyph |
706 &movecursor, // movecursor | 848 &movecursor, // movecursor |
710 NULL, // initpen | 852 NULL, // initpen |
711 &setpenattr, // setpenattr | 853 &setpenattr, // setpenattr |
712 &settermprop, // settermprop | 854 &settermprop, // settermprop |
713 &bell, // bell | 855 &bell, // bell |
714 &resize, // resize | 856 &resize, // resize |
715 &setlineinfo // setlineinfo | 857 &setlineinfo, // setlineinfo |
858 &sb_clear, //sb_clear | |
716 }; | 859 }; |
717 | 860 |
718 /* | 861 /* |
719 * Allocate a new screen and return it. | 862 * Allocate a new screen and return it. |
720 * Return NULL when out of memory. | 863 * Return NULL when out of memory. |
721 */ | 864 */ |
722 static VTermScreen *screen_new(VTerm *vt) | 865 static VTermScreen *screen_new(VTerm *vt) |
723 { | 866 { |
724 VTermState *state = vterm_obtain_state(vt); | 867 VTermState *state = vterm_obtain_state(vt); |
725 VTermScreen *screen; | 868 if(!state) |
726 int rows, cols; | |
727 | |
728 if (state == NULL) | |
729 return NULL; | 869 return NULL; |
730 screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); | 870 |
871 VTermScreen *screen = vterm_allocator_malloc(vt, sizeof(VTermScreen)); | |
731 if (screen == NULL) | 872 if (screen == NULL) |
732 return NULL; | 873 return NULL; |
874 int rows, cols; | |
733 | 875 |
734 vterm_get_size(vt, &rows, &cols); | 876 vterm_get_size(vt, &rows, &cols); |
735 | 877 |
736 screen->vt = vt; | 878 screen->vt = vt; |
737 screen->state = state; | 879 screen->state = state; |
740 screen->damaged.start_row = -1; | 882 screen->damaged.start_row = -1; |
741 screen->pending_scrollrect.start_row = -1; | 883 screen->pending_scrollrect.start_row = -1; |
742 | 884 |
743 screen->rows = rows; | 885 screen->rows = rows; |
744 screen->cols = cols; | 886 screen->cols = cols; |
887 | |
888 screen->global_reverse = FALSE; | |
889 screen->reflow = FALSE; | |
745 | 890 |
746 screen->callbacks = NULL; | 891 screen->callbacks = NULL; |
747 screen->cbdata = NULL; | 892 screen->cbdata = NULL; |
748 | 893 |
749 screen->buffers[BUFIDX_PRIMARY] = alloc_buffer(screen, rows, cols); | 894 screen->buffers[BUFIDX_PRIMARY] = alloc_buffer(screen, rows, cols); |
783 | 928 |
784 static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect) | 929 static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect) |
785 { | 930 { |
786 size_t outpos = 0; | 931 size_t outpos = 0; |
787 int padding = 0; | 932 int padding = 0; |
788 int row, col; | |
789 | 933 |
790 #define PUT(c) \ | 934 #define PUT(c) \ |
791 if(utf8) { \ | 935 if(utf8) { \ |
792 size_t thislen = utf8_seqlen(c); \ | 936 size_t thislen = utf8_seqlen(c); \ |
793 if(buffer && outpos + thislen <= len) \ | 937 if(buffer && outpos + thislen <= len) \ |
800 ((uint32_t*)buffer)[outpos++] = (c); \ | 944 ((uint32_t*)buffer)[outpos++] = (c); \ |
801 else \ | 945 else \ |
802 outpos++; \ | 946 outpos++; \ |
803 } | 947 } |
804 | 948 |
805 for(row = rect.start_row; row < rect.end_row; row++) { | 949 for(int row = rect.start_row; row < rect.end_row; row++) { |
806 for(col = rect.start_col; col < rect.end_col; col++) { | 950 for(int col = rect.start_col; col < rect.end_col; col++) { |
807 ScreenCell *cell = getcell(screen, row, col); | 951 ScreenCell *cell = getcell(screen, row, col); |
808 int i; | |
809 | 952 |
810 if (cell == NULL) | 953 if (cell == NULL) |
811 { | 954 { |
812 DEBUG_LOG2("libvterm: _get_chars() position invalid: %d / %d", | 955 DEBUG_LOG2("libvterm: _get_chars() position invalid: %d / %d", |
813 row, col); | 956 row, col); |
822 else { | 965 else { |
823 while(padding) { | 966 while(padding) { |
824 PUT(UNICODE_SPACE); | 967 PUT(UNICODE_SPACE); |
825 padding--; | 968 padding--; |
826 } | 969 } |
827 for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { | 970 for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { |
828 PUT(cell->chars[i]); | 971 PUT(cell->chars[i]); |
829 } | 972 } |
830 } | 973 } |
831 } | 974 } |
832 | 975 |
851 | 994 |
852 /* Copy internal to external representation of a screen cell */ | 995 /* Copy internal to external representation of a screen cell */ |
853 int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) | 996 int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) |
854 { | 997 { |
855 ScreenCell *intcell = getcell(screen, pos.row, pos.col); | 998 ScreenCell *intcell = getcell(screen, pos.row, pos.col); |
856 int i; | |
857 | 999 |
858 if(!intcell) | 1000 if(!intcell) |
859 return 0; | 1001 return 0; |
860 | 1002 |
861 for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { | 1003 for(int i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { |
862 cell->chars[i] = intcell->chars[i]; | 1004 cell->chars[i] = intcell->chars[i]; |
863 if(!intcell->chars[i]) | 1005 if(!intcell->chars[i]) |
864 break; | 1006 break; |
865 } | 1007 } |
866 | 1008 |
870 cell->attrs.blink = intcell->pen.blink; | 1012 cell->attrs.blink = intcell->pen.blink; |
871 cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse; | 1013 cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse; |
872 cell->attrs.conceal = intcell->pen.conceal; | 1014 cell->attrs.conceal = intcell->pen.conceal; |
873 cell->attrs.strike = intcell->pen.strike; | 1015 cell->attrs.strike = intcell->pen.strike; |
874 cell->attrs.font = intcell->pen.font; | 1016 cell->attrs.font = intcell->pen.font; |
1017 cell->attrs.small = intcell->pen.small; | |
1018 cell->attrs.baseline = intcell->pen.baseline; | |
875 | 1019 |
876 cell->attrs.dwl = intcell->pen.dwl; | 1020 cell->attrs.dwl = intcell->pen.dwl; |
877 cell->attrs.dhl = intcell->pen.dhl; | 1021 cell->attrs.dhl = intcell->pen.dhl; |
878 | 1022 |
879 cell->fg = intcell->pen.fg; | 1023 cell->fg = intcell->pen.fg; |
917 return 1; | 1061 return 1; |
918 } | 1062 } |
919 | 1063 |
920 VTermScreen *vterm_obtain_screen(VTerm *vt) | 1064 VTermScreen *vterm_obtain_screen(VTerm *vt) |
921 { | 1065 { |
922 if(!vt->screen) | 1066 if(vt->screen) |
923 vt->screen = screen_new(vt); | 1067 return vt->screen; |
1068 | |
1069 vt->screen = screen_new(vt); | |
924 return vt->screen; | 1070 return vt->screen; |
925 } | 1071 } |
1072 | |
1073 void vterm_screen_enable_reflow(VTermScreen *screen, int reflow) | |
1074 { | |
1075 screen->reflow = reflow; | |
1076 } | |
1077 | |
1078 // Removed, causes a compiler warning and isn't used | |
1079 // #undef vterm_screen_set_reflow | |
1080 // void vterm_screen_set_reflow(VTermScreen *screen, int reflow) | |
1081 // { | |
1082 // vterm_screen_enable_reflow(screen, reflow); | |
1083 // } | |
926 | 1084 |
927 void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) | 1085 void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) |
928 { | 1086 { |
929 if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { | 1087 if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { |
930 int rows, cols; | 1088 int rows, cols; |
998 return 1; | 1156 return 1; |
999 if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_is_equal(&a->pen.fg, &b->pen.fg)) | 1157 if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_is_equal(&a->pen.fg, &b->pen.fg)) |
1000 return 1; | 1158 return 1; |
1001 if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) | 1159 if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) |
1002 return 1; | 1160 return 1; |
1161 if((attrs & VTERM_ATTR_SMALL_MASK) && (a->pen.small != b->pen.small)) | |
1162 return 1; | |
1163 if((attrs & VTERM_ATTR_BASELINE_MASK) && (a->pen.baseline != b->pen.baseline)) | |
1164 return 1; | |
1003 | 1165 |
1004 return 0; | 1166 return 0; |
1005 } | 1167 } |
1006 | 1168 |
1007 int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs) | 1169 int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs) |
1008 { | 1170 { |
1009 int col; | |
1010 | |
1011 ScreenCell *target = getcell(screen, pos.row, pos.col); | 1171 ScreenCell *target = getcell(screen, pos.row, pos.col); |
1012 | 1172 |
1013 // TODO: bounds check | 1173 // TODO: bounds check |
1014 extent->start_row = pos.row; | 1174 extent->start_row = pos.row; |
1015 extent->end_row = pos.row + 1; | 1175 extent->end_row = pos.row + 1; |
1017 if(extent->start_col < 0) | 1177 if(extent->start_col < 0) |
1018 extent->start_col = 0; | 1178 extent->start_col = 0; |
1019 if(extent->end_col < 0) | 1179 if(extent->end_col < 0) |
1020 extent->end_col = screen->cols; | 1180 extent->end_col = screen->cols; |
1021 | 1181 |
1182 int col; | |
1183 | |
1022 for(col = pos.col - 1; col >= extent->start_col; col--) | 1184 for(col = pos.col - 1; col >= extent->start_col; col--) |
1023 if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) | 1185 if(attrs_differ(attrs, target, getcell(screen, pos.row, col))) |
1024 break; | 1186 break; |
1025 extent->start_col = col + 1; | 1187 extent->start_col = col + 1; |
1026 | 1188 |