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