• R/O
  • SSH

vim: Commit

Mirror of the Vim source from https://github.com/vim/vim


Commit MetaInfo

Revisionda6a7491e1482d8b68c39100acf04249019caaa5 (tree)
Time2019-10-10 20:30:04
AuthorBram Moolenaar <Bram@vim....>
CommiterBram Moolenaar

Log Message

patch 8.1.2128: renamed libvterm sources makes merging difficult

Commit: https://github.com/vim/vim/commit/93268054428fe3a6bbe3f89d2def2fec4eabcf5f
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Oct 10 13:22:54 2019 +0200

patch 8.1.2128: renamed libvterm sources makes merging difficult
Problem: Renamed libvterm sources makes merging difficult.
Solution: Rename back to the original name and only rename the .o files.
Also clean the libvterm build artifacts. (James McCoy,
closes #5027)

Change Summary

Incremental Difference

diff -r 4af19863e264 -r da6a7491e148 src/Make_cyg_ming.mak
--- a/src/Make_cyg_ming.mak Wed Oct 09 23:00:05 2019 +0200
+++ b/src/Make_cyg_ming.mak Thu Oct 10 13:30:04 2019 +0200
@@ -869,15 +869,15 @@
869869
870870 ifeq ($(TERMINAL),yes)
871871 OBJ += $(OUTDIR)/terminal.o \
872- $(OUTDIR)/encoding.o \
873- $(OUTDIR)/keyboard.o \
874- $(OUTDIR)/termmouse.o \
875- $(OUTDIR)/parser.o \
876- $(OUTDIR)/pen.o \
877- $(OUTDIR)/termscreen.o \
878- $(OUTDIR)/state.o \
879- $(OUTDIR)/unicode.o \
880- $(OUTDIR)/vterm.o
872+ $(OUTDIR)/vterm_encoding.o \
873+ $(OUTDIR)/vterm_keyboard.o \
874+ $(OUTDIR)/vterm_mouse.o \
875+ $(OUTDIR)/vterm_parser.o \
876+ $(OUTDIR)/vterm_pen.o \
877+ $(OUTDIR)/vterm_screen.o \
878+ $(OUTDIR)/vterm_state.o \
879+ $(OUTDIR)/vterm_unicode.o \
880+ $(OUTDIR)/vterm_vterm.o
881881 endif
882882
883883 ifeq ($(SOUND),yes)
@@ -1206,7 +1206,7 @@
12061206 -DWCWIDTH_FUNCTION=utf_uint2cells \
12071207 -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type
12081208
1209-$(OUTDIR)/%.o : libvterm/src/%.c $(TERM_DEPS)
1209+$(OUTDIR)/vterm_%.o : libvterm/src/%.c $(TERM_DEPS)
12101210 $(CCCTERM) $< -o $@
12111211
12121212
diff -r 4af19863e264 -r da6a7491e148 src/Make_mvc.mak
--- a/src/Make_mvc.mak Wed Oct 09 23:00:05 2019 +0200
+++ b/src/Make_mvc.mak Thu Oct 10 13:30:04 2019 +0200
@@ -363,15 +363,15 @@
363363 !if "$(TERMINAL)" == "yes"
364364 TERM_OBJ = \
365365 $(OBJDIR)/terminal.obj \
366- $(OBJDIR)/encoding.obj \
367- $(OBJDIR)/keyboard.obj \
368- $(OBJDIR)/termmouse.obj \
369- $(OBJDIR)/parser.obj \
370- $(OBJDIR)/pen.obj \
371- $(OBJDIR)/termscreen.obj \
372- $(OBJDIR)/state.obj \
373- $(OBJDIR)/unicode.obj \
374- $(OBJDIR)/vterm.obj
366+ $(OBJDIR)/vterm_encoding.obj \
367+ $(OBJDIR)/vterm_keyboard.obj \
368+ $(OBJDIR)/vterm_mouse.obj \
369+ $(OBJDIR)/vterm_parser.obj \
370+ $(OBJDIR)/vterm_pen.obj \
371+ $(OBJDIR)/vterm_screen.obj \
372+ $(OBJDIR)/vterm_state.obj \
373+ $(OBJDIR)/vterm_unicode.obj \
374+ $(OBJDIR)/vterm_vterm.obj
375375 TERM_DEFS = -DFEAT_TERMINAL
376376 TERM_DEPS = \
377377 libvterm/include/vterm.h \
@@ -1743,27 +1743,32 @@
17431743 -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type \
17441744 -D_CRT_SECURE_NO_WARNINGS
17451745
1746-# Create a default rule for libvterm.
1747-{libvterm/src/}.c{$(OUTDIR)/}.obj::
1748- $(CCCTERM) -Fo$(OUTDIR)/ $<
1749-
1750-$(OUTDIR)/encoding.obj: $(OUTDIR) libvterm/src/encoding.c $(TERM_DEPS)
1751-
1752-$(OUTDIR)/keyboard.obj: $(OUTDIR) libvterm/src/keyboard.c $(TERM_DEPS)
1753-
1754-$(OUTDIR)/termmouse.obj: $(OUTDIR) libvterm/src/termmouse.c $(TERM_DEPS)
1746+$(OUTDIR)/vterm_encoding.obj: $(OUTDIR) libvterm/src/encoding.c $(TERM_DEPS)
1747+ $(CCCTERM) /Fo$@ $<
17551748
1756-$(OUTDIR)/parser.obj: $(OUTDIR) libvterm/src/parser.c $(TERM_DEPS)
1757-
1758-$(OUTDIR)/pen.obj: $(OUTDIR) libvterm/src/pen.c $(TERM_DEPS)
1749+$(OUTDIR)/vterm_keyboard.obj: $(OUTDIR) libvterm/src/keyboard.c $(TERM_DEPS)
1750+ $(CCCTERM) /Fo$@ $<
17591751
1760-$(OUTDIR)/termscreen.obj: $(OUTDIR) libvterm/src/termscreen.c $(TERM_DEPS)
1752+$(OUTDIR)/vterm_mouse.obj: $(OUTDIR) libvterm/src/mouse.c $(TERM_DEPS)
1753+ $(CCCTERM) /Fo$@ $<
17611754
1762-$(OUTDIR)/state.obj: $(OUTDIR) libvterm/src/state.c $(TERM_DEPS)
1755+$(OUTDIR)/vterm_parser.obj: $(OUTDIR) libvterm/src/parser.c $(TERM_DEPS)
1756+ $(CCCTERM) /Fo$@ $<
17631757
1764-$(OUTDIR)/unicode.obj: $(OUTDIR) libvterm/src/unicode.c $(TERM_DEPS)
1758+$(OUTDIR)/vterm_pen.obj: $(OUTDIR) libvterm/src/pen.c $(TERM_DEPS)
1759+ $(CCCTERM) /Fo$@ $<
17651760
1766-$(OUTDIR)/vterm.obj: $(OUTDIR) libvterm/src/vterm.c $(TERM_DEPS)
1761+$(OUTDIR)/vterm_screen.obj: $(OUTDIR) libvterm/src/screen.c $(TERM_DEPS)
1762+ $(CCCTERM) /Fo$@ $<
1763+
1764+$(OUTDIR)/vterm_state.obj: $(OUTDIR) libvterm/src/state.c $(TERM_DEPS)
1765+ $(CCCTERM) /Fo$@ $<
1766+
1767+$(OUTDIR)/vterm_unicode.obj: $(OUTDIR) libvterm/src/unicode.c $(TERM_DEPS)
1768+ $(CCCTERM) /Fo$@ $<
1769+
1770+$(OUTDIR)/vterm_vterm.obj: $(OUTDIR) libvterm/src/vterm.c $(TERM_DEPS)
1771+ $(CCCTERM) /Fo$@ $<
17671772
17681773
17691774 # $CFLAGS may contain backslashes and double quotes, escape them both.
diff -r 4af19863e264 -r da6a7491e148 src/Makefile
--- a/src/Makefile Wed Oct 09 23:00:05 2019 +0200
+++ b/src/Makefile Thu Oct 10 13:30:04 2019 +0200
@@ -2860,6 +2860,7 @@
28602860 -rm -f runtime pixmaps
28612861 -rm -rf $(APPDIR)
28622862 -rm -rf mzscheme_base.c
2863+ -rm -rf libvterm/.libs libterm/t/.libs libvterm/src/*.o libvterm/src/*.lo libvterm/t/*.o libvterm/t/*.lo libvterm/t/harness libvterm/libvterm.la
28632864 if test -d $(PODIR); then \
28642865 cd $(PODIR); $(MAKE) prefix=$(DESTDIR)$(prefix) clean; \
28652866 fi
@@ -3453,36 +3454,39 @@
34533454 Makefile:
34543455 @echo The name of the makefile MUST be "Makefile" (with capital M)!!!!
34553456
3457+# Build rules for libvterm. Putting them here allows for adding compilation
3458+# options specific for Vim. Since the .o files go into objects/ we do need to
3459+# prefix vterm_ to avoid name clashes.
34563460 CCCTERM = $(CCC_NF) $(VTERM_CFLAGS) $(ALL_CFLAGS) -DINLINE="" \
34573461 -DVSNPRINTF=vim_vsnprintf \
34583462 -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \
34593463 -DWCWIDTH_FUNCTION=utf_uint2cells
34603464
3461-objects/encoding.o: libvterm/src/encoding.c $(TERM_DEPS)
3465+objects/vterm_encoding.o: libvterm/src/encoding.c $(TERM_DEPS)
34623466 $(CCCTERM) -o $@ libvterm/src/encoding.c
34633467
3464-objects/keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS)
3468+objects/vterm_keyboard.o: libvterm/src/keyboard.c $(TERM_DEPS)
34653469 $(CCCTERM) -o $@ libvterm/src/keyboard.c
34663470
3467-objects/termmouse.o: libvterm/src/termmouse.c $(TERM_DEPS)
3468- $(CCCTERM) -o $@ libvterm/src/termmouse.c
3469-
3470-objects/parser.o: libvterm/src/parser.c $(TERM_DEPS)
3471+objects/vterm_mouse.o: libvterm/src/mouse.c $(TERM_DEPS)
3472+ $(CCCTERM) -o $@ libvterm/src/mouse.c
3473+
3474+objects/vterm_parser.o: libvterm/src/parser.c $(TERM_DEPS)
34713475 $(CCCTERM) -o $@ libvterm/src/parser.c
34723476
3473-objects/pen.o: libvterm/src/pen.c $(TERM_DEPS)
3477+objects/vterm_pen.o: libvterm/src/pen.c $(TERM_DEPS)
34743478 $(CCCTERM) -o $@ libvterm/src/pen.c
34753479
3476-objects/termscreen.o: libvterm/src/termscreen.c $(TERM_DEPS)
3477- $(CCCTERM) -o $@ libvterm/src/termscreen.c
3478-
3479-objects/state.o: libvterm/src/state.c $(TERM_DEPS)
3480+objects/vterm_screen.o: libvterm/src/screen.c $(TERM_DEPS)
3481+ $(CCCTERM) -o $@ libvterm/src/screen.c
3482+
3483+objects/vterm_state.o: libvterm/src/state.c $(TERM_DEPS)
34803484 $(CCCTERM) -o $@ libvterm/src/state.c
34813485
3482-objects/unicode.o: libvterm/src/unicode.c $(TERM_DEPS)
3486+objects/vterm_unicode.o: libvterm/src/unicode.c $(TERM_DEPS)
34833487 $(CCCTERM) -o $@ libvterm/src/unicode.c
34843488
3485-objects/vterm.o: libvterm/src/vterm.c $(TERM_DEPS)
3489+objects/vterm_vterm.o: libvterm/src/vterm.c $(TERM_DEPS)
34863490 $(CCCTERM) -o $@ libvterm/src/vterm.c
34873491
34883492 CCCDIFF = $(CCC_NF) $(ALL_CFLAGS)
@@ -4111,27 +4115,27 @@
41114115 proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
41124116 proto.h globals.h
41134117 objects/gui_gtk_gresources.o: auto/gui_gtk_gresources.c
4114-objects/encoding.o: libvterm/src/encoding.c libvterm/src/vterm_internal.h \
4118+objects/vterm_encoding.o: libvterm/src/encoding.c libvterm/src/vterm_internal.h \
41154119 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
41164120 libvterm/src/encoding/DECdrawing.inc libvterm/src/encoding/uk.inc
4117-objects/keyboard.o: libvterm/src/keyboard.c libvterm/src/vterm_internal.h \
4118- libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
4119- libvterm/src/utf8.h
4120-objects/termmouse.o: libvterm/src/termmouse.c libvterm/src/vterm_internal.h \
4121+objects/vterm_keyboard.o: libvterm/src/keyboard.c libvterm/src/vterm_internal.h \
41214122 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
41224123 libvterm/src/utf8.h
4123-objects/parser.o: libvterm/src/parser.c libvterm/src/vterm_internal.h \
4124+objects/vterm_mouse.o: libvterm/src/mouse.c libvterm/src/vterm_internal.h \
4125+ libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
4126+ libvterm/src/utf8.h
4127+objects/vterm_parser.o: libvterm/src/parser.c libvterm/src/vterm_internal.h \
41244128 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
4125-objects/pen.o: libvterm/src/pen.c libvterm/src/vterm_internal.h \
4129+objects/vterm_pen.o: libvterm/src/pen.c libvterm/src/vterm_internal.h \
41264130 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
4127-objects/state.o: libvterm/src/state.c libvterm/src/vterm_internal.h \
4131+objects/vterm_state.o: libvterm/src/state.c libvterm/src/vterm_internal.h \
41284132 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
4129-objects/termscreen.o: libvterm/src/termscreen.c libvterm/src/vterm_internal.h \
4133+objects/vterm_screen.o: libvterm/src/screen.c libvterm/src/vterm_internal.h \
41304134 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
41314135 libvterm/src/rect.h libvterm/src/utf8.h
4132-objects/unicode.o: libvterm/src/unicode.c libvterm/src/vterm_internal.h \
4136+objects/vterm_unicode.o: libvterm/src/unicode.c libvterm/src/vterm_internal.h \
41334137 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h
4134-objects/vterm.o: libvterm/src/vterm.c libvterm/src/vterm_internal.h \
4138+objects/vterm_vterm.o: libvterm/src/vterm.c libvterm/src/vterm_internal.h \
41354139 libvterm/include/vterm.h libvterm/include/vterm_keycodes.h \
41364140 libvterm/src/utf8.h
41374141 objects/xdiffi.o: xdiff/xdiffi.c xdiff/xinclude.h auto/config.h \
diff -r 4af19863e264 -r da6a7491e148 src/auto/configure
--- a/src/auto/configure Wed Oct 09 23:00:05 2019 +0200
+++ b/src/auto/configure Thu Oct 10 13:30:04 2019 +0200
@@ -7907,9 +7907,9 @@
79077907 if test "$enable_terminal" = "yes" -a "$enable_channel" = "yes"; then
79087908 $as_echo "#define FEAT_TERMINAL 1" >>confdefs.h
79097909
7910- TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/termscreen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
7911-
7912- TERM_OBJ="objects/encoding.o objects/keyboard.o objects/termmouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
7910+ TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/creen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
7911+
7912+ TERM_OBJ="objects/vterm_encoding.o objects/vterm_keyboard.o objects/vterm_mouse.o objects/vterm_parser.o objects/vterm_pen.o objects/vterm_screen.o objects/vterm_state.o objects/vterm_unicode.o objects/vterm_vterm.o"
79137913
79147914 fi
79157915
diff -r 4af19863e264 -r da6a7491e148 src/configure.ac
--- a/src/configure.ac Wed Oct 09 23:00:05 2019 +0200
+++ b/src/configure.ac Thu Oct 10 13:30:04 2019 +0200
@@ -2104,9 +2104,9 @@
21042104 fi
21052105 if test "$enable_terminal" = "yes" -a "$enable_channel" = "yes"; then
21062106 AC_DEFINE(FEAT_TERMINAL)
2107- TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/termscreen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
2107+ TERM_SRC="libvterm/src/encoding.c libvterm/src/keyboard.c libvterm/src/mouse.c libvterm/src/parser.c libvterm/src/pen.c libvterm/src/creen.c libvterm/src/state.c libvterm/src/unicode.c libvterm/src/vterm.c"
21082108 AC_SUBST(TERM_SRC)
2109- TERM_OBJ="objects/encoding.o objects/keyboard.o objects/termmouse.o objects/parser.o objects/pen.o objects/termscreen.o objects/state.o objects/unicode.o objects/vterm.o"
2109+ TERM_OBJ="objects/vterm_encoding.o objects/vterm_keyboard.o objects/vterm_mouse.o objects/vterm_parser.o objects/vterm_pen.o objects/vterm_screen.o objects/vterm_state.o objects/vterm_unicode.o objects/vterm_vterm.o"
21102110 AC_SUBST(TERM_OBJ)
21112111 fi
21122112
diff -r 4af19863e264 -r da6a7491e148 src/libvterm/src/mouse.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libvterm/src/mouse.c Thu Oct 10 13:30:04 2019 +0200
@@ -0,0 +1,98 @@
1+#include "vterm_internal.h"
2+
3+#include "utf8.h"
4+
5+static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)
6+{
7+ modifiers <<= 2;
8+
9+ switch(state->mouse_protocol) {
10+ case MOUSE_X10:
11+ if(col + 0x21 > 0xff)
12+ col = 0xff - 0x21;
13+ if(row + 0x21 > 0xff)
14+ row = 0xff - 0x21;
15+
16+ if(!pressed)
17+ code = 3;
18+
19+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
20+ (code | modifiers) + 0x20, col + 0x21, row + 0x21);
21+ break;
22+
23+ case MOUSE_UTF8:
24+ {
25+ char utf8[18]; size_t len = 0;
26+
27+ if(!pressed)
28+ code = 3;
29+
30+ len += fill_utf8((code | modifiers) + 0x20, utf8 + len);
31+ len += fill_utf8(col + 0x21, utf8 + len);
32+ len += fill_utf8(row + 0x21, utf8 + len);
33+ utf8[len] = 0;
34+
35+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8);
36+ }
37+ break;
38+
39+ case MOUSE_SGR:
40+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c",
41+ code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm');
42+ break;
43+
44+ case MOUSE_RXVT:
45+ if(!pressed)
46+ code = 3;
47+
48+ vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM",
49+ code | modifiers, col + 1, row + 1);
50+ break;
51+ }
52+}
53+
54+void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
55+{
56+ VTermState *state = vt->state;
57+
58+ if(col == state->mouse_col && row == state->mouse_row)
59+ return;
60+
61+ state->mouse_col = col;
62+ state->mouse_row = row;
63+
64+ if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||
65+ (state->mouse_flags & MOUSE_WANT_MOVE)) {
66+ int button = state->mouse_buttons & MOUSE_BUTTON_LEFT ? 1 :
67+ state->mouse_buttons & MOUSE_BUTTON_MIDDLE ? 2 :
68+ state->mouse_buttons & MOUSE_BUTTON_RIGHT ? 3 : 4;
69+ output_mouse(state, button-1 + 0x20, 1, mod, col, row);
70+ }
71+}
72+
73+void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod)
74+{
75+ VTermState *state = vt->state;
76+
77+ int old_buttons = state->mouse_buttons;
78+
79+ if(button > 0 && button <= 3) {
80+ if(pressed)
81+ state->mouse_buttons |= (1 << (button-1));
82+ else
83+ state->mouse_buttons &= ~(1 << (button-1));
84+ }
85+
86+ // Most of the time we don't get button releases from 4/5
87+ if(state->mouse_buttons == old_buttons && button < 4)
88+ return;
89+ if (!(state->mouse_flags & MOUSE_WANT_CLICK))
90+ return;
91+
92+ if(button < 4) {
93+ output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);
94+ }
95+ else if(button < 6) {
96+ output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row);
97+ }
98+}
diff -r 4af19863e264 -r da6a7491e148 src/libvterm/src/screen.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libvterm/src/screen.c Thu Oct 10 13:30:04 2019 +0200
@@ -0,0 +1,958 @@
1+#include "vterm_internal.h"
2+
3+// vim: set sw=2 :
4+#include <stdio.h>
5+#include <string.h>
6+
7+#include "rect.h"
8+#include "utf8.h"
9+
10+#define UNICODE_SPACE 0x20
11+#define UNICODE_LINEFEED 0x0a
12+
13+// State of the pen at some moment in time, also used in a cell
14+typedef struct
15+{
16+ // After the bitfield
17+ VTermColor fg, bg;
18+
19+ unsigned int bold : 1;
20+ unsigned int underline : 2;
21+ unsigned int italic : 1;
22+ unsigned int blink : 1;
23+ unsigned int reverse : 1;
24+ unsigned int strike : 1;
25+ unsigned int font : 4; // 0 to 9
26+
27+ // Extra state storage that isn't strictly pen-related
28+ unsigned int protected_cell : 1;
29+ unsigned int dwl : 1; // on a DECDWL or DECDHL line
30+ unsigned int dhl : 2; // on a DECDHL line (1=top 2=bottom)
31+} ScreenPen;
32+
33+// Internal representation of a screen cell
34+typedef struct
35+{
36+ uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
37+ ScreenPen pen;
38+} ScreenCell;
39+
40+static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell);
41+
42+struct VTermScreen
43+{
44+ VTerm *vt;
45+ VTermState *state;
46+
47+ const VTermScreenCallbacks *callbacks;
48+ void *cbdata;
49+
50+ VTermDamageSize damage_merge;
51+ // start_row == -1 => no damage
52+ VTermRect damaged;
53+ VTermRect pending_scrollrect;
54+ int pending_scroll_downward, pending_scroll_rightward;
55+
56+ int rows;
57+ int cols;
58+ int global_reverse;
59+
60+ // Primary and Altscreen. buffers[1] is lazily allocated as needed
61+ ScreenCell *buffers[2];
62+
63+ // buffer will == buffers[0] or buffers[1], depending on altscreen
64+ ScreenCell *buffer;
65+
66+ // buffer for a single screen row used in scrollback storage callbacks
67+ VTermScreenCell *sb_buffer;
68+
69+ ScreenPen pen;
70+};
71+
72+static ScreenCell *getcell(const VTermScreen *screen, int row, int col)
73+{
74+ if(row < 0 || row >= screen->rows)
75+ return NULL;
76+ if(col < 0 || col >= screen->cols)
77+ return NULL;
78+ if (screen->buffer == NULL)
79+ return NULL;
80+ return screen->buffer + (screen->cols * row) + col;
81+}
82+
83+static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols)
84+{
85+ ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols);
86+ int row, col;
87+
88+ if (new_buffer == NULL)
89+ return NULL;
90+ for(row = 0; row < new_rows; row++) {
91+ for(col = 0; col < new_cols; col++) {
92+ ScreenCell *new_cell = new_buffer + row*new_cols + col;
93+
94+ if(buffer && row < screen->rows && col < screen->cols)
95+ *new_cell = buffer[row * screen->cols + col];
96+ else {
97+ new_cell->chars[0] = 0;
98+ new_cell->pen = screen->pen;
99+ }
100+ }
101+ }
102+
103+ vterm_allocator_free(screen->vt, buffer);
104+
105+ return new_buffer;
106+}
107+
108+static void damagerect(VTermScreen *screen, VTermRect rect)
109+{
110+ VTermRect emit;
111+
112+ switch(screen->damage_merge) {
113+ case VTERM_DAMAGE_CELL:
114+ // Always emit damage event
115+ emit = rect;
116+ break;
117+
118+ case VTERM_DAMAGE_ROW:
119+ // Emit damage longer than one row. Try to merge with existing damage in
120+ // the same row
121+ if(rect.end_row > rect.start_row + 1) {
122+ // Bigger than 1 line - flush existing, emit this
123+ vterm_screen_flush_damage(screen);
124+ emit = rect;
125+ }
126+ else if(screen->damaged.start_row == -1) {
127+ // None stored yet
128+ screen->damaged = rect;
129+ return;
130+ }
131+ else if(rect.start_row == screen->damaged.start_row) {
132+ // Merge with the stored line
133+ if(screen->damaged.start_col > rect.start_col)
134+ screen->damaged.start_col = rect.start_col;
135+ if(screen->damaged.end_col < rect.end_col)
136+ screen->damaged.end_col = rect.end_col;
137+ return;
138+ }
139+ else {
140+ // Emit the currently stored line, store a new one
141+ emit = screen->damaged;
142+ screen->damaged = rect;
143+ }
144+ break;
145+
146+ case VTERM_DAMAGE_SCREEN:
147+ case VTERM_DAMAGE_SCROLL:
148+ // Never emit damage event
149+ if(screen->damaged.start_row == -1)
150+ screen->damaged = rect;
151+ else {
152+ rect_expand(&screen->damaged, &rect);
153+ }
154+ return;
155+
156+ default:
157+ DEBUG_LOG1("TODO: Maybe merge damage for level %d\n", screen->damage_merge);
158+ return;
159+ }
160+
161+ if(screen->callbacks && screen->callbacks->damage)
162+ (*screen->callbacks->damage)(emit, screen->cbdata);
163+}
164+
165+static void damagescreen(VTermScreen *screen)
166+{
167+ VTermRect rect = {0,0,0,0};
168+ rect.end_row = screen->rows;
169+ rect.end_col = screen->cols;
170+
171+ damagerect(screen, rect);
172+}
173+
174+static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
175+{
176+ int i;
177+ int col;
178+ VTermRect rect;
179+
180+ VTermScreen *screen = user;
181+ ScreenCell *cell = getcell(screen, pos.row, pos.col);
182+
183+ if(!cell)
184+ return 0;
185+
186+ for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
187+ cell->chars[i] = info->chars[i];
188+ cell->pen = screen->pen;
189+ }
190+ if(i < VTERM_MAX_CHARS_PER_CELL)
191+ cell->chars[i] = 0;
192+
193+ for(col = 1; col < info->width; col++)
194+ getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1;
195+
196+ rect.start_row = pos.row;
197+ rect.end_row = pos.row+1;
198+ rect.start_col = pos.col;
199+ rect.end_col = pos.col+info->width;
200+
201+ cell->pen.protected_cell = info->protected_cell;
202+ cell->pen.dwl = info->dwl;
203+ cell->pen.dhl = info->dhl;
204+
205+ damagerect(screen, rect);
206+
207+ return 1;
208+}
209+
210+static int moverect_internal(VTermRect dest, VTermRect src, void *user)
211+{
212+ VTermScreen *screen = user;
213+
214+ if(screen->callbacks && screen->callbacks->sb_pushline &&
215+ dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner
216+ dest.end_col == screen->cols && // full width
217+ screen->buffer == screen->buffers[0]) { // not altscreen
218+ VTermPos pos;
219+ for(pos.row = 0; pos.row < src.start_row; pos.row++) {
220+ for(pos.col = 0; pos.col < screen->cols; pos.col++)
221+ (void)vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col);
222+
223+ (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata);
224+ }
225+ }
226+
227+ {
228+ int cols = src.end_col - src.start_col;
229+ int downward = src.start_row - dest.start_row;
230+ int init_row, test_row, inc_row;
231+ int row;
232+
233+ if(downward < 0) {
234+ init_row = dest.end_row - 1;
235+ test_row = dest.start_row - 1;
236+ inc_row = -1;
237+ }
238+ else {
239+ init_row = dest.start_row;
240+ test_row = dest.end_row;
241+ inc_row = +1;
242+ }
243+
244+ for(row = init_row; row != test_row; row += inc_row)
245+ memmove(getcell(screen, row, dest.start_col),
246+ getcell(screen, row + downward, src.start_col),
247+ cols * sizeof(ScreenCell));
248+ }
249+
250+ return 1;
251+}
252+
253+static int moverect_user(VTermRect dest, VTermRect src, void *user)
254+{
255+ VTermScreen *screen = user;
256+
257+ if(screen->callbacks && screen->callbacks->moverect) {
258+ if(screen->damage_merge != VTERM_DAMAGE_SCROLL)
259+ // Avoid an infinite loop
260+ vterm_screen_flush_damage(screen);
261+
262+ if((*screen->callbacks->moverect)(dest, src, screen->cbdata))
263+ return 1;
264+ }
265+
266+ damagerect(screen, dest);
267+
268+ return 1;
269+}
270+
271+static int erase_internal(VTermRect rect, int selective, void *user)
272+{
273+ VTermScreen *screen = user;
274+ int row, col;
275+
276+ for(row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) {
277+ const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row);
278+
279+ for(col = rect.start_col; col < rect.end_col; col++) {
280+ ScreenCell *cell = getcell(screen, row, col);
281+
282+ if(selective && cell->pen.protected_cell)
283+ continue;
284+
285+ cell->chars[0] = 0;
286+ cell->pen = screen->pen;
287+ cell->pen.dwl = info->doublewidth;
288+ cell->pen.dhl = info->doubleheight;
289+ }
290+ }
291+
292+ return 1;
293+}
294+
295+static int erase_user(VTermRect rect, int selective UNUSED, void *user)
296+{
297+ VTermScreen *screen = user;
298+
299+ damagerect(screen, rect);
300+
301+ return 1;
302+}
303+
304+static int erase(VTermRect rect, int selective, void *user)
305+{
306+ erase_internal(rect, selective, user);
307+ return erase_user(rect, 0, user);
308+}
309+
310+static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
311+{
312+ VTermScreen *screen = user;
313+
314+ if(screen->damage_merge != VTERM_DAMAGE_SCROLL) {
315+ vterm_scroll_rect(rect, downward, rightward,
316+ moverect_internal, erase_internal, screen);
317+
318+ vterm_screen_flush_damage(screen);
319+
320+ vterm_scroll_rect(rect, downward, rightward,
321+ moverect_user, erase_user, screen);
322+
323+ return 1;
324+ }
325+
326+ if(screen->damaged.start_row != -1 &&
327+ !rect_intersects(&rect, &screen->damaged)) {
328+ vterm_screen_flush_damage(screen);
329+ }
330+
331+ if(screen->pending_scrollrect.start_row == -1) {
332+ screen->pending_scrollrect = rect;
333+ screen->pending_scroll_downward = downward;
334+ screen->pending_scroll_rightward = rightward;
335+ }
336+ else if(rect_equal(&screen->pending_scrollrect, &rect) &&
337+ ((screen->pending_scroll_downward == 0 && downward == 0) ||
338+ (screen->pending_scroll_rightward == 0 && rightward == 0))) {
339+ screen->pending_scroll_downward += downward;
340+ screen->pending_scroll_rightward += rightward;
341+ }
342+ else {
343+ vterm_screen_flush_damage(screen);
344+
345+ screen->pending_scrollrect = rect;
346+ screen->pending_scroll_downward = downward;
347+ screen->pending_scroll_rightward = rightward;
348+ }
349+
350+ vterm_scroll_rect(rect, downward, rightward,
351+ moverect_internal, erase_internal, screen);
352+
353+ if(screen->damaged.start_row == -1)
354+ return 1;
355+
356+ if(rect_contains(&rect, &screen->damaged)) {
357+ // Scroll region entirely contains the damage; just move it
358+ vterm_rect_move(&screen->damaged, -downward, -rightward);
359+ rect_clip(&screen->damaged, &rect);
360+ }
361+ // There are a number of possible cases here, but lets restrict this to only
362+ // the common case where we might actually gain some performance by
363+ // optimising it. Namely, a vertical scroll that neatly cuts the damage
364+ // region in half.
365+ else if(rect.start_col <= screen->damaged.start_col &&
366+ rect.end_col >= screen->damaged.end_col &&
367+ rightward == 0) {
368+ if(screen->damaged.start_row >= rect.start_row &&
369+ screen->damaged.start_row < rect.end_row) {
370+ screen->damaged.start_row -= downward;
371+ if(screen->damaged.start_row < rect.start_row)
372+ screen->damaged.start_row = rect.start_row;
373+ if(screen->damaged.start_row > rect.end_row)
374+ screen->damaged.start_row = rect.end_row;
375+ }
376+ if(screen->damaged.end_row >= rect.start_row &&
377+ screen->damaged.end_row < rect.end_row) {
378+ screen->damaged.end_row -= downward;
379+ if(screen->damaged.end_row < rect.start_row)
380+ screen->damaged.end_row = rect.start_row;
381+ if(screen->damaged.end_row > rect.end_row)
382+ screen->damaged.end_row = rect.end_row;
383+ }
384+ }
385+ else {
386+ DEBUG_LOG2("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n",
387+ ARGSrect(screen->damaged), ARGSrect(rect));
388+ }
389+
390+ return 1;
391+}
392+
393+static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
394+{
395+ VTermScreen *screen = user;
396+
397+ if(screen->callbacks && screen->callbacks->movecursor)
398+ return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata);
399+
400+ return 0;
401+}
402+
403+static int setpenattr(VTermAttr attr, VTermValue *val, void *user)
404+{
405+ VTermScreen *screen = user;
406+
407+ switch(attr) {
408+ case VTERM_ATTR_BOLD:
409+ screen->pen.bold = val->boolean;
410+ return 1;
411+ case VTERM_ATTR_UNDERLINE:
412+ screen->pen.underline = val->number;
413+ return 1;
414+ case VTERM_ATTR_ITALIC:
415+ screen->pen.italic = val->boolean;
416+ return 1;
417+ case VTERM_ATTR_BLINK:
418+ screen->pen.blink = val->boolean;
419+ return 1;
420+ case VTERM_ATTR_REVERSE:
421+ screen->pen.reverse = val->boolean;
422+ return 1;
423+ case VTERM_ATTR_STRIKE:
424+ screen->pen.strike = val->boolean;
425+ return 1;
426+ case VTERM_ATTR_FONT:
427+ screen->pen.font = val->number;
428+ return 1;
429+ case VTERM_ATTR_FOREGROUND:
430+ screen->pen.fg = val->color;
431+ return 1;
432+ case VTERM_ATTR_BACKGROUND:
433+ screen->pen.bg = val->color;
434+ return 1;
435+
436+ case VTERM_N_ATTRS:
437+ return 0;
438+ }
439+
440+ return 0;
441+}
442+
443+static int settermprop(VTermProp prop, VTermValue *val, void *user)
444+{
445+ VTermScreen *screen = user;
446+
447+ switch(prop) {
448+ case VTERM_PROP_ALTSCREEN:
449+ if(val->boolean && !screen->buffers[1])
450+ return 0;
451+
452+ screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0];
453+ // only send a damage event on disable; because during enable there's an
454+ // erase that sends a damage anyway
455+ if(!val->boolean)
456+ damagescreen(screen);
457+ break;
458+ case VTERM_PROP_REVERSE:
459+ screen->global_reverse = val->boolean;
460+ damagescreen(screen);
461+ break;
462+ default:
463+ ; // ignore
464+ }
465+
466+ if(screen->callbacks && screen->callbacks->settermprop)
467+ return (*screen->callbacks->settermprop)(prop, val, screen->cbdata);
468+
469+ return 1;
470+}
471+
472+static int bell(void *user)
473+{
474+ VTermScreen *screen = user;
475+
476+ if(screen->callbacks && screen->callbacks->bell)
477+ return (*screen->callbacks->bell)(screen->cbdata);
478+
479+ return 0;
480+}
481+
482+static int resize(int new_rows, int new_cols, VTermPos *delta, void *user)
483+{
484+ VTermScreen *screen = user;
485+
486+ int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]);
487+
488+ int old_rows = screen->rows;
489+ int old_cols = screen->cols;
490+ int first_blank_row;
491+
492+ if(!is_altscreen && new_rows < old_rows) {
493+ // Fewer rows - determine if we're going to scroll at all, and if so, push
494+ // those lines to scrollback
495+ VTermPos pos = { 0, 0 };
496+ VTermPos cursor = screen->state->pos;
497+ // Find the first blank row after the cursor.
498+ for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--)
499+ if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row)
500+ break;
501+
502+ first_blank_row = pos.row + 1;
503+ if(first_blank_row > new_rows) {
504+ VTermRect rect = {0,0,0,0};
505+ rect.end_row = old_rows;
506+ rect.end_col = old_cols;
507+ scrollrect(rect, first_blank_row - new_rows, 0, user);
508+ vterm_screen_flush_damage(screen);
509+
510+ delta->row -= first_blank_row - new_rows;
511+ }
512+ }
513+
514+ screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols);
515+ if(screen->buffers[1])
516+ screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols);
517+
518+ screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0];
519+
520+ screen->rows = new_rows;
521+ screen->cols = new_cols;
522+
523+ vterm_allocator_free(screen->vt, screen->sb_buffer);
524+
525+ screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);
526+
527+ if(new_cols > old_cols) {
528+ VTermRect rect;
529+ rect.start_row = 0;
530+ rect.end_row = old_rows;
531+ rect.start_col = old_cols;
532+ rect.end_col = new_cols;
533+ damagerect(screen, rect);
534+ }
535+
536+ if(new_rows > old_rows) {
537+ if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) {
538+ int rows = new_rows - old_rows;
539+ while(rows) {
540+ VTermRect rect = {0,0,0,0};
541+ VTermPos pos = { 0, 0 };
542+ if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata)))
543+ break;
544+
545+ rect.end_row = screen->rows;
546+ rect.end_col = screen->cols;
547+ scrollrect(rect, -1, 0, user);
548+
549+ for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width)
550+ vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col);
551+
552+ rect.end_row = 1;
553+ damagerect(screen, rect);
554+
555+ vterm_screen_flush_damage(screen);
556+
557+ rows--;
558+ delta->row++;
559+ }
560+ }
561+
562+ {
563+ VTermRect rect;
564+ rect.start_row = old_rows;
565+ rect.end_row = new_rows;
566+ rect.start_col = 0;
567+ rect.end_col = new_cols;
568+ damagerect(screen, rect);
569+ }
570+ }
571+
572+ if(screen->callbacks && screen->callbacks->resize)
573+ return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata);
574+
575+ return 1;
576+}
577+
578+static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)
579+{
580+ VTermScreen *screen = user;
581+ int col;
582+ VTermRect rect;
583+
584+ if(newinfo->doublewidth != oldinfo->doublewidth ||
585+ newinfo->doubleheight != oldinfo->doubleheight) {
586+ for(col = 0; col < screen->cols; col++) {
587+ ScreenCell *cell = getcell(screen, row, col);
588+ cell->pen.dwl = newinfo->doublewidth;
589+ cell->pen.dhl = newinfo->doubleheight;
590+ }
591+
592+ rect.start_row = row;
593+ rect.end_row = row + 1;
594+ rect.start_col = 0;
595+ rect.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols;
596+ damagerect(screen, rect);
597+
598+ if(newinfo->doublewidth) {
599+ rect.start_col = screen->cols / 2;
600+ rect.end_col = screen->cols;
601+
602+ erase_internal(rect, 0, user);
603+ }
604+ }
605+
606+ return 1;
607+}
608+
609+static VTermStateCallbacks state_cbs = {
610+ &putglyph, // putglyph
611+ &movecursor, // movecursor
612+ &scrollrect, // scrollrect
613+ NULL, // moverect
614+ &erase, // erase
615+ NULL, // initpen
616+ &setpenattr, // setpenattr
617+ &settermprop, // settermprop
618+ &bell, // bell
619+ &resize, // resize
620+ &setlineinfo // setlineinfo
621+};
622+
623+/*
624+ * Allocate a new screen and return it.
625+ * Return NULL when out of memory.
626+ */
627+static VTermScreen *screen_new(VTerm *vt)
628+{
629+ VTermState *state = vterm_obtain_state(vt);
630+ VTermScreen *screen;
631+ int rows, cols;
632+
633+ if (state == NULL)
634+ return NULL;
635+ screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
636+ if (screen == NULL)
637+ return NULL;
638+
639+ vterm_get_size(vt, &rows, &cols);
640+
641+ screen->vt = vt;
642+ screen->state = state;
643+
644+ screen->damage_merge = VTERM_DAMAGE_CELL;
645+ screen->damaged.start_row = -1;
646+ screen->pending_scrollrect.start_row = -1;
647+
648+ screen->rows = rows;
649+ screen->cols = cols;
650+
651+ screen->callbacks = NULL;
652+ screen->cbdata = NULL;
653+
654+ screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols);
655+ screen->buffer = screen->buffers[0];
656+ screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);
657+ if (screen->buffer == NULL || screen->sb_buffer == NULL)
658+ {
659+ vterm_screen_free(screen);
660+ return NULL;
661+ }
662+
663+ vterm_state_set_callbacks(screen->state, &state_cbs, screen);
664+
665+ return screen;
666+}
667+
668+INTERNAL void vterm_screen_free(VTermScreen *screen)
669+{
670+ vterm_allocator_free(screen->vt, screen->buffers[0]);
671+ vterm_allocator_free(screen->vt, screen->buffers[1]);
672+ vterm_allocator_free(screen->vt, screen->sb_buffer);
673+ vterm_allocator_free(screen->vt, screen);
674+}
675+
676+void vterm_screen_reset(VTermScreen *screen, int hard)
677+{
678+ screen->damaged.start_row = -1;
679+ screen->pending_scrollrect.start_row = -1;
680+ vterm_state_reset(screen->state, hard);
681+ vterm_screen_flush_damage(screen);
682+}
683+
684+static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect)
685+{
686+ size_t outpos = 0;
687+ int padding = 0;
688+ int row, col;
689+
690+#define PUT(c) \
691+ if(utf8) { \
692+ size_t thislen = utf8_seqlen(c); \
693+ if(buffer && outpos + thislen <= len) \
694+ outpos += fill_utf8((c), (char *)buffer + outpos); \
695+ else \
696+ outpos += thislen; \
697+ } \
698+ else { \
699+ if(buffer && outpos + 1 <= len) \
700+ ((uint32_t*)buffer)[outpos++] = (c); \
701+ else \
702+ outpos++; \
703+ }
704+
705+ for(row = rect.start_row; row < rect.end_row; row++) {
706+ for(col = rect.start_col; col < rect.end_col; col++) {
707+ ScreenCell *cell = getcell(screen, row, col);
708+ int i;
709+
710+ if(cell->chars[0] == 0)
711+ // Erased cell, might need a space
712+ padding++;
713+ else if(cell->chars[0] == (uint32_t)-1)
714+ // Gap behind a double-width char, do nothing
715+ ;
716+ else {
717+ while(padding) {
718+ PUT(UNICODE_SPACE);
719+ padding--;
720+ }
721+ for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
722+ PUT(cell->chars[i]);
723+ }
724+ }
725+ }
726+
727+ if(row < rect.end_row - 1) {
728+ PUT(UNICODE_LINEFEED);
729+ padding = 0;
730+ }
731+ }
732+
733+ return outpos;
734+}
735+
736+size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect)
737+{
738+ return _get_chars(screen, 0, chars, len, rect);
739+}
740+
741+size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect)
742+{
743+ return _get_chars(screen, 1, str, len, rect);
744+}
745+
746+// Copy internal to external representation of a screen cell
747+int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)
748+{
749+ ScreenCell *intcell = getcell(screen, pos.row, pos.col);
750+ int i;
751+
752+ if(!intcell)
753+ return 0;
754+
755+ for(i = 0; ; i++) {
756+ cell->chars[i] = intcell->chars[i];
757+ if(!intcell->chars[i])
758+ break;
759+ }
760+
761+ cell->attrs.bold = intcell->pen.bold;
762+ cell->attrs.underline = intcell->pen.underline;
763+ cell->attrs.italic = intcell->pen.italic;
764+ cell->attrs.blink = intcell->pen.blink;
765+ cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse;
766+ cell->attrs.strike = intcell->pen.strike;
767+ cell->attrs.font = intcell->pen.font;
768+
769+ cell->attrs.dwl = intcell->pen.dwl;
770+ cell->attrs.dhl = intcell->pen.dhl;
771+
772+ cell->fg = intcell->pen.fg;
773+ cell->bg = intcell->pen.bg;
774+
775+ if(vterm_get_special_pty_type() == 2) {
776+ /* Get correct cell width from cell information contained in line buffer */
777+ if(pos.col < (screen->cols - 1) &&
778+ getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) {
779+ if(getcell(screen, pos.row, pos.col)->chars[0] == 0x20) {
780+ getcell(screen, pos.row, pos.col)->chars[0] = 0;
781+ cell->width = 2;
782+ } else if(getcell(screen, pos.row, pos.col)->chars[0] == 0) {
783+ getcell(screen, pos.row, pos.col + 1)->chars[0] = 0;
784+ cell->width = 1;
785+ } else {
786+ cell->width = 2;
787+ }
788+ } else
789+ cell->width = 1;
790+ } else {
791+ if(pos.col < (screen->cols - 1) &&
792+ getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1)
793+ cell->width = 2;
794+ else
795+ cell->width = 1;
796+ }
797+
798+ return 1;
799+}
800+
801+// Copy external to internal representation of a screen cell
802+/* static because it's only used internally for sb_popline during resize */
803+static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell)
804+{
805+ ScreenCell *intcell = getcell(screen, pos.row, pos.col);
806+ int i;
807+
808+ if(!intcell)
809+ return 0;
810+
811+ for(i = 0; ; i++) {
812+ intcell->chars[i] = cell->chars[i];
813+ if(!cell->chars[i])
814+ break;
815+ }
816+
817+ intcell->pen.bold = cell->attrs.bold;
818+ intcell->pen.underline = cell->attrs.underline;
819+ intcell->pen.italic = cell->attrs.italic;
820+ intcell->pen.blink = cell->attrs.blink;
821+ intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse;
822+ intcell->pen.strike = cell->attrs.strike;
823+ intcell->pen.font = cell->attrs.font;
824+
825+ intcell->pen.fg = cell->fg;
826+ intcell->pen.bg = cell->bg;
827+
828+ if(cell->width == 2)
829+ getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1;
830+
831+ return 1;
832+}
833+
834+int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos)
835+{
836+ // This cell is EOL if this and every cell to the right is black
837+ for(; pos.col < screen->cols; pos.col++) {
838+ ScreenCell *cell = getcell(screen, pos.row, pos.col);
839+ if(cell->chars[0] != 0)
840+ return 0;
841+ }
842+
843+ return 1;
844+}
845+
846+VTermScreen *vterm_obtain_screen(VTerm *vt)
847+{
848+ if(!vt->screen)
849+ vt->screen = screen_new(vt);
850+ return vt->screen;
851+}
852+
853+void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen)
854+{
855+
856+ if(!screen->buffers[1] && altscreen) {
857+ int rows, cols;
858+ vterm_get_size(screen->vt, &rows, &cols);
859+
860+ screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols);
861+ }
862+}
863+
864+void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user)
865+{
866+ screen->callbacks = callbacks;
867+ screen->cbdata = user;
868+}
869+
870+void *vterm_screen_get_cbdata(VTermScreen *screen)
871+{
872+ return screen->cbdata;
873+}
874+
875+void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user)
876+{
877+ vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user);
878+}
879+
880+void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen)
881+{
882+ return vterm_state_get_unrecognised_fbdata(screen->state);
883+}
884+
885+void vterm_screen_flush_damage(VTermScreen *screen)
886+{
887+ if(screen->pending_scrollrect.start_row != -1) {
888+ vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward,
889+ moverect_user, erase_user, screen);
890+
891+ screen->pending_scrollrect.start_row = -1;
892+ }
893+
894+ if(screen->damaged.start_row != -1) {
895+ if(screen->callbacks && screen->callbacks->damage)
896+ (*screen->callbacks->damage)(screen->damaged, screen->cbdata);
897+
898+ screen->damaged.start_row = -1;
899+ }
900+}
901+
902+void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size)
903+{
904+ vterm_screen_flush_damage(screen);
905+ screen->damage_merge = size;
906+}
907+
908+static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b)
909+{
910+ if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold))
911+ return 1;
912+ if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline))
913+ return 1;
914+ if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic))
915+ return 1;
916+ if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink))
917+ return 1;
918+ if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse))
919+ return 1;
920+ if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike))
921+ return 1;
922+ if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font))
923+ return 1;
924+ if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg))
925+ return 1;
926+ if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg))
927+ return 1;
928+
929+ return 0;
930+}
931+
932+int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs)
933+{
934+ int col;
935+
936+ ScreenCell *target = getcell(screen, pos.row, pos.col);
937+
938+ // TODO: bounds check
939+ extent->start_row = pos.row;
940+ extent->end_row = pos.row + 1;
941+
942+ if(extent->start_col < 0)
943+ extent->start_col = 0;
944+ if(extent->end_col < 0)
945+ extent->end_col = screen->cols;
946+
947+ for(col = pos.col - 1; col >= extent->start_col; col--)
948+ if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
949+ break;
950+ extent->start_col = col + 1;
951+
952+ for(col = pos.col + 1; col < extent->end_col; col++)
953+ if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
954+ break;
955+ extent->end_col = col - 1;
956+
957+ return 1;
958+}
diff -r 4af19863e264 -r da6a7491e148 src/libvterm/src/termmouse.c
--- a/src/libvterm/src/termmouse.c Wed Oct 09 23:00:05 2019 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
1-#include "vterm_internal.h"
2-
3-#include "utf8.h"
4-
5-static void output_mouse(VTermState *state, int code, int pressed, int modifiers, int col, int row)
6-{
7- modifiers <<= 2;
8-
9- switch(state->mouse_protocol) {
10- case MOUSE_X10:
11- if(col + 0x21 > 0xff)
12- col = 0xff - 0x21;
13- if(row + 0x21 > 0xff)
14- row = 0xff - 0x21;
15-
16- if(!pressed)
17- code = 3;
18-
19- vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%c%c%c",
20- (code | modifiers) + 0x20, col + 0x21, row + 0x21);
21- break;
22-
23- case MOUSE_UTF8:
24- {
25- char utf8[18]; size_t len = 0;
26-
27- if(!pressed)
28- code = 3;
29-
30- len += fill_utf8((code | modifiers) + 0x20, utf8 + len);
31- len += fill_utf8(col + 0x21, utf8 + len);
32- len += fill_utf8(row + 0x21, utf8 + len);
33- utf8[len] = 0;
34-
35- vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8);
36- }
37- break;
38-
39- case MOUSE_SGR:
40- vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "<%d;%d;%d%c",
41- code | modifiers, col + 1, row + 1, pressed ? 'M' : 'm');
42- break;
43-
44- case MOUSE_RXVT:
45- if(!pressed)
46- code = 3;
47-
48- vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "%d;%d;%dM",
49- code | modifiers, col + 1, row + 1);
50- break;
51- }
52-}
53-
54-void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
55-{
56- VTermState *state = vt->state;
57-
58- if(col == state->mouse_col && row == state->mouse_row)
59- return;
60-
61- state->mouse_col = col;
62- state->mouse_row = row;
63-
64- if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||
65- (state->mouse_flags & MOUSE_WANT_MOVE)) {
66- int button = state->mouse_buttons & MOUSE_BUTTON_LEFT ? 1 :
67- state->mouse_buttons & MOUSE_BUTTON_MIDDLE ? 2 :
68- state->mouse_buttons & MOUSE_BUTTON_RIGHT ? 3 : 4;
69- output_mouse(state, button-1 + 0x20, 1, mod, col, row);
70- }
71-}
72-
73-void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod)
74-{
75- VTermState *state = vt->state;
76-
77- int old_buttons = state->mouse_buttons;
78-
79- if(button > 0 && button <= 3) {
80- if(pressed)
81- state->mouse_buttons |= (1 << (button-1));
82- else
83- state->mouse_buttons &= ~(1 << (button-1));
84- }
85-
86- // Most of the time we don't get button releases from 4/5
87- if(state->mouse_buttons == old_buttons && button < 4)
88- return;
89- if (!(state->mouse_flags & MOUSE_WANT_CLICK))
90- return;
91-
92- if(button < 4) {
93- output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);
94- }
95- else if(button < 6) {
96- output_mouse(state, button-4 + 0x40, pressed, mod, state->mouse_col, state->mouse_row);
97- }
98-}
diff -r 4af19863e264 -r da6a7491e148 src/libvterm/src/termscreen.c
--- a/src/libvterm/src/termscreen.c Wed Oct 09 23:00:05 2019 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,958 +0,0 @@
1-#include "vterm_internal.h"
2-
3-// vim: set sw=2 :
4-#include <stdio.h>
5-#include <string.h>
6-
7-#include "rect.h"
8-#include "utf8.h"
9-
10-#define UNICODE_SPACE 0x20
11-#define UNICODE_LINEFEED 0x0a
12-
13-// State of the pen at some moment in time, also used in a cell
14-typedef struct
15-{
16- // After the bitfield
17- VTermColor fg, bg;
18-
19- unsigned int bold : 1;
20- unsigned int underline : 2;
21- unsigned int italic : 1;
22- unsigned int blink : 1;
23- unsigned int reverse : 1;
24- unsigned int strike : 1;
25- unsigned int font : 4; // 0 to 9
26-
27- // Extra state storage that isn't strictly pen-related
28- unsigned int protected_cell : 1;
29- unsigned int dwl : 1; // on a DECDWL or DECDHL line
30- unsigned int dhl : 2; // on a DECDHL line (1=top 2=bottom)
31-} ScreenPen;
32-
33-// Internal representation of a screen cell
34-typedef struct
35-{
36- uint32_t chars[VTERM_MAX_CHARS_PER_CELL];
37- ScreenPen pen;
38-} ScreenCell;
39-
40-static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell);
41-
42-struct VTermScreen
43-{
44- VTerm *vt;
45- VTermState *state;
46-
47- const VTermScreenCallbacks *callbacks;
48- void *cbdata;
49-
50- VTermDamageSize damage_merge;
51- // start_row == -1 => no damage
52- VTermRect damaged;
53- VTermRect pending_scrollrect;
54- int pending_scroll_downward, pending_scroll_rightward;
55-
56- int rows;
57- int cols;
58- int global_reverse;
59-
60- // Primary and Altscreen. buffers[1] is lazily allocated as needed
61- ScreenCell *buffers[2];
62-
63- // buffer will == buffers[0] or buffers[1], depending on altscreen
64- ScreenCell *buffer;
65-
66- // buffer for a single screen row used in scrollback storage callbacks
67- VTermScreenCell *sb_buffer;
68-
69- ScreenPen pen;
70-};
71-
72-static ScreenCell *getcell(const VTermScreen *screen, int row, int col)
73-{
74- if(row < 0 || row >= screen->rows)
75- return NULL;
76- if(col < 0 || col >= screen->cols)
77- return NULL;
78- if (screen->buffer == NULL)
79- return NULL;
80- return screen->buffer + (screen->cols * row) + col;
81-}
82-
83-static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols)
84-{
85- ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols);
86- int row, col;
87-
88- if (new_buffer == NULL)
89- return NULL;
90- for(row = 0; row < new_rows; row++) {
91- for(col = 0; col < new_cols; col++) {
92- ScreenCell *new_cell = new_buffer + row*new_cols + col;
93-
94- if(buffer && row < screen->rows && col < screen->cols)
95- *new_cell = buffer[row * screen->cols + col];
96- else {
97- new_cell->chars[0] = 0;
98- new_cell->pen = screen->pen;
99- }
100- }
101- }
102-
103- vterm_allocator_free(screen->vt, buffer);
104-
105- return new_buffer;
106-}
107-
108-static void damagerect(VTermScreen *screen, VTermRect rect)
109-{
110- VTermRect emit;
111-
112- switch(screen->damage_merge) {
113- case VTERM_DAMAGE_CELL:
114- // Always emit damage event
115- emit = rect;
116- break;
117-
118- case VTERM_DAMAGE_ROW:
119- // Emit damage longer than one row. Try to merge with existing damage in
120- // the same row
121- if(rect.end_row > rect.start_row + 1) {
122- // Bigger than 1 line - flush existing, emit this
123- vterm_screen_flush_damage(screen);
124- emit = rect;
125- }
126- else if(screen->damaged.start_row == -1) {
127- // None stored yet
128- screen->damaged = rect;
129- return;
130- }
131- else if(rect.start_row == screen->damaged.start_row) {
132- // Merge with the stored line
133- if(screen->damaged.start_col > rect.start_col)
134- screen->damaged.start_col = rect.start_col;
135- if(screen->damaged.end_col < rect.end_col)
136- screen->damaged.end_col = rect.end_col;
137- return;
138- }
139- else {
140- // Emit the currently stored line, store a new one
141- emit = screen->damaged;
142- screen->damaged = rect;
143- }
144- break;
145-
146- case VTERM_DAMAGE_SCREEN:
147- case VTERM_DAMAGE_SCROLL:
148- // Never emit damage event
149- if(screen->damaged.start_row == -1)
150- screen->damaged = rect;
151- else {
152- rect_expand(&screen->damaged, &rect);
153- }
154- return;
155-
156- default:
157- DEBUG_LOG1("TODO: Maybe merge damage for level %d\n", screen->damage_merge);
158- return;
159- }
160-
161- if(screen->callbacks && screen->callbacks->damage)
162- (*screen->callbacks->damage)(emit, screen->cbdata);
163-}
164-
165-static void damagescreen(VTermScreen *screen)
166-{
167- VTermRect rect = {0,0,0,0};
168- rect.end_row = screen->rows;
169- rect.end_col = screen->cols;
170-
171- damagerect(screen, rect);
172-}
173-
174-static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
175-{
176- int i;
177- int col;
178- VTermRect rect;
179-
180- VTermScreen *screen = user;
181- ScreenCell *cell = getcell(screen, pos.row, pos.col);
182-
183- if(!cell)
184- return 0;
185-
186- for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) {
187- cell->chars[i] = info->chars[i];
188- cell->pen = screen->pen;
189- }
190- if(i < VTERM_MAX_CHARS_PER_CELL)
191- cell->chars[i] = 0;
192-
193- for(col = 1; col < info->width; col++)
194- getcell(screen, pos.row, pos.col + col)->chars[0] = (uint32_t)-1;
195-
196- rect.start_row = pos.row;
197- rect.end_row = pos.row+1;
198- rect.start_col = pos.col;
199- rect.end_col = pos.col+info->width;
200-
201- cell->pen.protected_cell = info->protected_cell;
202- cell->pen.dwl = info->dwl;
203- cell->pen.dhl = info->dhl;
204-
205- damagerect(screen, rect);
206-
207- return 1;
208-}
209-
210-static int moverect_internal(VTermRect dest, VTermRect src, void *user)
211-{
212- VTermScreen *screen = user;
213-
214- if(screen->callbacks && screen->callbacks->sb_pushline &&
215- dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner
216- dest.end_col == screen->cols && // full width
217- screen->buffer == screen->buffers[0]) { // not altscreen
218- VTermPos pos;
219- for(pos.row = 0; pos.row < src.start_row; pos.row++) {
220- for(pos.col = 0; pos.col < screen->cols; pos.col++)
221- (void)vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col);
222-
223- (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata);
224- }
225- }
226-
227- {
228- int cols = src.end_col - src.start_col;
229- int downward = src.start_row - dest.start_row;
230- int init_row, test_row, inc_row;
231- int row;
232-
233- if(downward < 0) {
234- init_row = dest.end_row - 1;
235- test_row = dest.start_row - 1;
236- inc_row = -1;
237- }
238- else {
239- init_row = dest.start_row;
240- test_row = dest.end_row;
241- inc_row = +1;
242- }
243-
244- for(row = init_row; row != test_row; row += inc_row)
245- memmove(getcell(screen, row, dest.start_col),
246- getcell(screen, row + downward, src.start_col),
247- cols * sizeof(ScreenCell));
248- }
249-
250- return 1;
251-}
252-
253-static int moverect_user(VTermRect dest, VTermRect src, void *user)
254-{
255- VTermScreen *screen = user;
256-
257- if(screen->callbacks && screen->callbacks->moverect) {
258- if(screen->damage_merge != VTERM_DAMAGE_SCROLL)
259- // Avoid an infinite loop
260- vterm_screen_flush_damage(screen);
261-
262- if((*screen->callbacks->moverect)(dest, src, screen->cbdata))
263- return 1;
264- }
265-
266- damagerect(screen, dest);
267-
268- return 1;
269-}
270-
271-static int erase_internal(VTermRect rect, int selective, void *user)
272-{
273- VTermScreen *screen = user;
274- int row, col;
275-
276- for(row = rect.start_row; row < screen->state->rows && row < rect.end_row; row++) {
277- const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row);
278-
279- for(col = rect.start_col; col < rect.end_col; col++) {
280- ScreenCell *cell = getcell(screen, row, col);
281-
282- if(selective && cell->pen.protected_cell)
283- continue;
284-
285- cell->chars[0] = 0;
286- cell->pen = screen->pen;
287- cell->pen.dwl = info->doublewidth;
288- cell->pen.dhl = info->doubleheight;
289- }
290- }
291-
292- return 1;
293-}
294-
295-static int erase_user(VTermRect rect, int selective UNUSED, void *user)
296-{
297- VTermScreen *screen = user;
298-
299- damagerect(screen, rect);
300-
301- return 1;
302-}
303-
304-static int erase(VTermRect rect, int selective, void *user)
305-{
306- erase_internal(rect, selective, user);
307- return erase_user(rect, 0, user);
308-}
309-
310-static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
311-{
312- VTermScreen *screen = user;
313-
314- if(screen->damage_merge != VTERM_DAMAGE_SCROLL) {
315- vterm_scroll_rect(rect, downward, rightward,
316- moverect_internal, erase_internal, screen);
317-
318- vterm_screen_flush_damage(screen);
319-
320- vterm_scroll_rect(rect, downward, rightward,
321- moverect_user, erase_user, screen);
322-
323- return 1;
324- }
325-
326- if(screen->damaged.start_row != -1 &&
327- !rect_intersects(&rect, &screen->damaged)) {
328- vterm_screen_flush_damage(screen);
329- }
330-
331- if(screen->pending_scrollrect.start_row == -1) {
332- screen->pending_scrollrect = rect;
333- screen->pending_scroll_downward = downward;
334- screen->pending_scroll_rightward = rightward;
335- }
336- else if(rect_equal(&screen->pending_scrollrect, &rect) &&
337- ((screen->pending_scroll_downward == 0 && downward == 0) ||
338- (screen->pending_scroll_rightward == 0 && rightward == 0))) {
339- screen->pending_scroll_downward += downward;
340- screen->pending_scroll_rightward += rightward;
341- }
342- else {
343- vterm_screen_flush_damage(screen);
344-
345- screen->pending_scrollrect = rect;
346- screen->pending_scroll_downward = downward;
347- screen->pending_scroll_rightward = rightward;
348- }
349-
350- vterm_scroll_rect(rect, downward, rightward,
351- moverect_internal, erase_internal, screen);
352-
353- if(screen->damaged.start_row == -1)
354- return 1;
355-
356- if(rect_contains(&rect, &screen->damaged)) {
357- // Scroll region entirely contains the damage; just move it
358- vterm_rect_move(&screen->damaged, -downward, -rightward);
359- rect_clip(&screen->damaged, &rect);
360- }
361- // There are a number of possible cases here, but lets restrict this to only
362- // the common case where we might actually gain some performance by
363- // optimising it. Namely, a vertical scroll that neatly cuts the damage
364- // region in half.
365- else if(rect.start_col <= screen->damaged.start_col &&
366- rect.end_col >= screen->damaged.end_col &&
367- rightward == 0) {
368- if(screen->damaged.start_row >= rect.start_row &&
369- screen->damaged.start_row < rect.end_row) {
370- screen->damaged.start_row -= downward;
371- if(screen->damaged.start_row < rect.start_row)
372- screen->damaged.start_row = rect.start_row;
373- if(screen->damaged.start_row > rect.end_row)
374- screen->damaged.start_row = rect.end_row;
375- }
376- if(screen->damaged.end_row >= rect.start_row &&
377- screen->damaged.end_row < rect.end_row) {
378- screen->damaged.end_row -= downward;
379- if(screen->damaged.end_row < rect.start_row)
380- screen->damaged.end_row = rect.start_row;
381- if(screen->damaged.end_row > rect.end_row)
382- screen->damaged.end_row = rect.end_row;
383- }
384- }
385- else {
386- DEBUG_LOG2("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n",
387- ARGSrect(screen->damaged), ARGSrect(rect));
388- }
389-
390- return 1;
391-}
392-
393-static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
394-{
395- VTermScreen *screen = user;
396-
397- if(screen->callbacks && screen->callbacks->movecursor)
398- return (*screen->callbacks->movecursor)(pos, oldpos, visible, screen->cbdata);
399-
400- return 0;
401-}
402-
403-static int setpenattr(VTermAttr attr, VTermValue *val, void *user)
404-{
405- VTermScreen *screen = user;
406-
407- switch(attr) {
408- case VTERM_ATTR_BOLD:
409- screen->pen.bold = val->boolean;
410- return 1;
411- case VTERM_ATTR_UNDERLINE:
412- screen->pen.underline = val->number;
413- return 1;
414- case VTERM_ATTR_ITALIC:
415- screen->pen.italic = val->boolean;
416- return 1;
417- case VTERM_ATTR_BLINK:
418- screen->pen.blink = val->boolean;
419- return 1;
420- case VTERM_ATTR_REVERSE:
421- screen->pen.reverse = val->boolean;
422- return 1;
423- case VTERM_ATTR_STRIKE:
424- screen->pen.strike = val->boolean;
425- return 1;
426- case VTERM_ATTR_FONT:
427- screen->pen.font = val->number;
428- return 1;
429- case VTERM_ATTR_FOREGROUND:
430- screen->pen.fg = val->color;
431- return 1;
432- case VTERM_ATTR_BACKGROUND:
433- screen->pen.bg = val->color;
434- return 1;
435-
436- case VTERM_N_ATTRS:
437- return 0;
438- }
439-
440- return 0;
441-}
442-
443-static int settermprop(VTermProp prop, VTermValue *val, void *user)
444-{
445- VTermScreen *screen = user;
446-
447- switch(prop) {
448- case VTERM_PROP_ALTSCREEN:
449- if(val->boolean && !screen->buffers[1])
450- return 0;
451-
452- screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0];
453- // only send a damage event on disable; because during enable there's an
454- // erase that sends a damage anyway
455- if(!val->boolean)
456- damagescreen(screen);
457- break;
458- case VTERM_PROP_REVERSE:
459- screen->global_reverse = val->boolean;
460- damagescreen(screen);
461- break;
462- default:
463- ; // ignore
464- }
465-
466- if(screen->callbacks && screen->callbacks->settermprop)
467- return (*screen->callbacks->settermprop)(prop, val, screen->cbdata);
468-
469- return 1;
470-}
471-
472-static int bell(void *user)
473-{
474- VTermScreen *screen = user;
475-
476- if(screen->callbacks && screen->callbacks->bell)
477- return (*screen->callbacks->bell)(screen->cbdata);
478-
479- return 0;
480-}
481-
482-static int resize(int new_rows, int new_cols, VTermPos *delta, void *user)
483-{
484- VTermScreen *screen = user;
485-
486- int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]);
487-
488- int old_rows = screen->rows;
489- int old_cols = screen->cols;
490- int first_blank_row;
491-
492- if(!is_altscreen && new_rows < old_rows) {
493- // Fewer rows - determine if we're going to scroll at all, and if so, push
494- // those lines to scrollback
495- VTermPos pos = { 0, 0 };
496- VTermPos cursor = screen->state->pos;
497- // Find the first blank row after the cursor.
498- for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--)
499- if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row)
500- break;
501-
502- first_blank_row = pos.row + 1;
503- if(first_blank_row > new_rows) {
504- VTermRect rect = {0,0,0,0};
505- rect.end_row = old_rows;
506- rect.end_col = old_cols;
507- scrollrect(rect, first_blank_row - new_rows, 0, user);
508- vterm_screen_flush_damage(screen);
509-
510- delta->row -= first_blank_row - new_rows;
511- }
512- }
513-
514- screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols);
515- if(screen->buffers[1])
516- screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols);
517-
518- screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0];
519-
520- screen->rows = new_rows;
521- screen->cols = new_cols;
522-
523- vterm_allocator_free(screen->vt, screen->sb_buffer);
524-
525- screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols);
526-
527- if(new_cols > old_cols) {
528- VTermRect rect;
529- rect.start_row = 0;
530- rect.end_row = old_rows;
531- rect.start_col = old_cols;
532- rect.end_col = new_cols;
533- damagerect(screen, rect);
534- }
535-
536- if(new_rows > old_rows) {
537- if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) {
538- int rows = new_rows - old_rows;
539- while(rows) {
540- VTermRect rect = {0,0,0,0};
541- VTermPos pos = { 0, 0 };
542- if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata)))
543- break;
544-
545- rect.end_row = screen->rows;
546- rect.end_col = screen->cols;
547- scrollrect(rect, -1, 0, user);
548-
549- for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width)
550- vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col);
551-
552- rect.end_row = 1;
553- damagerect(screen, rect);
554-
555- vterm_screen_flush_damage(screen);
556-
557- rows--;
558- delta->row++;
559- }
560- }
561-
562- {
563- VTermRect rect;
564- rect.start_row = old_rows;
565- rect.end_row = new_rows;
566- rect.start_col = 0;
567- rect.end_col = new_cols;
568- damagerect(screen, rect);
569- }
570- }
571-
572- if(screen->callbacks && screen->callbacks->resize)
573- return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata);
574-
575- return 1;
576-}
577-
578-static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)
579-{
580- VTermScreen *screen = user;
581- int col;
582- VTermRect rect;
583-
584- if(newinfo->doublewidth != oldinfo->doublewidth ||
585- newinfo->doubleheight != oldinfo->doubleheight) {
586- for(col = 0; col < screen->cols; col++) {
587- ScreenCell *cell = getcell(screen, row, col);
588- cell->pen.dwl = newinfo->doublewidth;
589- cell->pen.dhl = newinfo->doubleheight;
590- }
591-
592- rect.start_row = row;
593- rect.end_row = row + 1;
594- rect.start_col = 0;
595- rect.end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols;
596- damagerect(screen, rect);
597-
598- if(newinfo->doublewidth) {
599- rect.start_col = screen->cols / 2;
600- rect.end_col = screen->cols;
601-
602- erase_internal(rect, 0, user);
603- }
604- }
605-
606- return 1;
607-}
608-
609-static VTermStateCallbacks state_cbs = {
610- &putglyph, // putglyph
611- &movecursor, // movecursor
612- &scrollrect, // scrollrect
613- NULL, // moverect
614- &erase, // erase
615- NULL, // initpen
616- &setpenattr, // setpenattr
617- &settermprop, // settermprop
618- &bell, // bell
619- &resize, // resize
620- &setlineinfo // setlineinfo
621-};
622-
623-/*
624- * Allocate a new screen and return it.
625- * Return NULL when out of memory.
626- */
627-static VTermScreen *screen_new(VTerm *vt)
628-{
629- VTermState *state = vterm_obtain_state(vt);
630- VTermScreen *screen;
631- int rows, cols;
632-
633- if (state == NULL)
634- return NULL;
635- screen = vterm_allocator_malloc(vt, sizeof(VTermScreen));
636- if (screen == NULL)
637- return NULL;
638-
639- vterm_get_size(vt, &rows, &cols);
640-
641- screen->vt = vt;
642- screen->state = state;
643-
644- screen->damage_merge = VTERM_DAMAGE_CELL;
645- screen->damaged.start_row = -1;
646- screen->pending_scrollrect.start_row = -1;
647-
648- screen->rows = rows;
649- screen->cols = cols;
650-
651- screen->callbacks = NULL;
652- screen->cbdata = NULL;
653-
654- screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols);
655- screen->buffer = screen->buffers[0];
656- screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols);
657- if (screen->buffer == NULL || screen->sb_buffer == NULL)
658- {
659- vterm_screen_free(screen);
660- return NULL;
661- }
662-
663- vterm_state_set_callbacks(screen->state, &state_cbs, screen);
664-
665- return screen;
666-}
667-
668-INTERNAL void vterm_screen_free(VTermScreen *screen)
669-{
670- vterm_allocator_free(screen->vt, screen->buffers[0]);
671- vterm_allocator_free(screen->vt, screen->buffers[1]);
672- vterm_allocator_free(screen->vt, screen->sb_buffer);
673- vterm_allocator_free(screen->vt, screen);
674-}
675-
676-void vterm_screen_reset(VTermScreen *screen, int hard)
677-{
678- screen->damaged.start_row = -1;
679- screen->pending_scrollrect.start_row = -1;
680- vterm_state_reset(screen->state, hard);
681- vterm_screen_flush_damage(screen);
682-}
683-
684-static size_t _get_chars(const VTermScreen *screen, const int utf8, void *buffer, size_t len, const VTermRect rect)
685-{
686- size_t outpos = 0;
687- int padding = 0;
688- int row, col;
689-
690-#define PUT(c) \
691- if(utf8) { \
692- size_t thislen = utf8_seqlen(c); \
693- if(buffer && outpos + thislen <= len) \
694- outpos += fill_utf8((c), (char *)buffer + outpos); \
695- else \
696- outpos += thislen; \
697- } \
698- else { \
699- if(buffer && outpos + 1 <= len) \
700- ((uint32_t*)buffer)[outpos++] = (c); \
701- else \
702- outpos++; \
703- }
704-
705- for(row = rect.start_row; row < rect.end_row; row++) {
706- for(col = rect.start_col; col < rect.end_col; col++) {
707- ScreenCell *cell = getcell(screen, row, col);
708- int i;
709-
710- if(cell->chars[0] == 0)
711- // Erased cell, might need a space
712- padding++;
713- else if(cell->chars[0] == (uint32_t)-1)
714- // Gap behind a double-width char, do nothing
715- ;
716- else {
717- while(padding) {
718- PUT(UNICODE_SPACE);
719- padding--;
720- }
721- for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) {
722- PUT(cell->chars[i]);
723- }
724- }
725- }
726-
727- if(row < rect.end_row - 1) {
728- PUT(UNICODE_LINEFEED);
729- padding = 0;
730- }
731- }
732-
733- return outpos;
734-}
735-
736-size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect)
737-{
738- return _get_chars(screen, 0, chars, len, rect);
739-}
740-
741-size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect)
742-{
743- return _get_chars(screen, 1, str, len, rect);
744-}
745-
746-// Copy internal to external representation of a screen cell
747-int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell)
748-{
749- ScreenCell *intcell = getcell(screen, pos.row, pos.col);
750- int i;
751-
752- if(!intcell)
753- return 0;
754-
755- for(i = 0; ; i++) {
756- cell->chars[i] = intcell->chars[i];
757- if(!intcell->chars[i])
758- break;
759- }
760-
761- cell->attrs.bold = intcell->pen.bold;
762- cell->attrs.underline = intcell->pen.underline;
763- cell->attrs.italic = intcell->pen.italic;
764- cell->attrs.blink = intcell->pen.blink;
765- cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse;
766- cell->attrs.strike = intcell->pen.strike;
767- cell->attrs.font = intcell->pen.font;
768-
769- cell->attrs.dwl = intcell->pen.dwl;
770- cell->attrs.dhl = intcell->pen.dhl;
771-
772- cell->fg = intcell->pen.fg;
773- cell->bg = intcell->pen.bg;
774-
775- if(vterm_get_special_pty_type() == 2) {
776- /* Get correct cell width from cell information contained in line buffer */
777- if(pos.col < (screen->cols - 1) &&
778- getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1) {
779- if(getcell(screen, pos.row, pos.col)->chars[0] == 0x20) {
780- getcell(screen, pos.row, pos.col)->chars[0] = 0;
781- cell->width = 2;
782- } else if(getcell(screen, pos.row, pos.col)->chars[0] == 0) {
783- getcell(screen, pos.row, pos.col + 1)->chars[0] = 0;
784- cell->width = 1;
785- } else {
786- cell->width = 2;
787- }
788- } else
789- cell->width = 1;
790- } else {
791- if(pos.col < (screen->cols - 1) &&
792- getcell(screen, pos.row, pos.col + 1)->chars[0] == (uint32_t)-1)
793- cell->width = 2;
794- else
795- cell->width = 1;
796- }
797-
798- return 1;
799-}
800-
801-// Copy external to internal representation of a screen cell
802-/* static because it's only used internally for sb_popline during resize */
803-static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell)
804-{
805- ScreenCell *intcell = getcell(screen, pos.row, pos.col);
806- int i;
807-
808- if(!intcell)
809- return 0;
810-
811- for(i = 0; ; i++) {
812- intcell->chars[i] = cell->chars[i];
813- if(!cell->chars[i])
814- break;
815- }
816-
817- intcell->pen.bold = cell->attrs.bold;
818- intcell->pen.underline = cell->attrs.underline;
819- intcell->pen.italic = cell->attrs.italic;
820- intcell->pen.blink = cell->attrs.blink;
821- intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse;
822- intcell->pen.strike = cell->attrs.strike;
823- intcell->pen.font = cell->attrs.font;
824-
825- intcell->pen.fg = cell->fg;
826- intcell->pen.bg = cell->bg;
827-
828- if(cell->width == 2)
829- getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1;
830-
831- return 1;
832-}
833-
834-int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos)
835-{
836- // This cell is EOL if this and every cell to the right is black
837- for(; pos.col < screen->cols; pos.col++) {
838- ScreenCell *cell = getcell(screen, pos.row, pos.col);
839- if(cell->chars[0] != 0)
840- return 0;
841- }
842-
843- return 1;
844-}
845-
846-VTermScreen *vterm_obtain_screen(VTerm *vt)
847-{
848- if(!vt->screen)
849- vt->screen = screen_new(vt);
850- return vt->screen;
851-}
852-
853-void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen)
854-{
855-
856- if(!screen->buffers[1] && altscreen) {
857- int rows, cols;
858- vterm_get_size(screen->vt, &rows, &cols);
859-
860- screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols);
861- }
862-}
863-
864-void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user)
865-{
866- screen->callbacks = callbacks;
867- screen->cbdata = user;
868-}
869-
870-void *vterm_screen_get_cbdata(VTermScreen *screen)
871-{
872- return screen->cbdata;
873-}
874-
875-void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user)
876-{
877- vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user);
878-}
879-
880-void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen)
881-{
882- return vterm_state_get_unrecognised_fbdata(screen->state);
883-}
884-
885-void vterm_screen_flush_damage(VTermScreen *screen)
886-{
887- if(screen->pending_scrollrect.start_row != -1) {
888- vterm_scroll_rect(screen->pending_scrollrect, screen->pending_scroll_downward, screen->pending_scroll_rightward,
889- moverect_user, erase_user, screen);
890-
891- screen->pending_scrollrect.start_row = -1;
892- }
893-
894- if(screen->damaged.start_row != -1) {
895- if(screen->callbacks && screen->callbacks->damage)
896- (*screen->callbacks->damage)(screen->damaged, screen->cbdata);
897-
898- screen->damaged.start_row = -1;
899- }
900-}
901-
902-void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size)
903-{
904- vterm_screen_flush_damage(screen);
905- screen->damage_merge = size;
906-}
907-
908-static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b)
909-{
910- if((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold))
911- return 1;
912- if((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline))
913- return 1;
914- if((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic))
915- return 1;
916- if((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink))
917- return 1;
918- if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse))
919- return 1;
920- if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike))
921- return 1;
922- if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font))
923- return 1;
924- if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg))
925- return 1;
926- if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg))
927- return 1;
928-
929- return 0;
930-}
931-
932-int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs)
933-{
934- int col;
935-
936- ScreenCell *target = getcell(screen, pos.row, pos.col);
937-
938- // TODO: bounds check
939- extent->start_row = pos.row;
940- extent->end_row = pos.row + 1;
941-
942- if(extent->start_col < 0)
943- extent->start_col = 0;
944- if(extent->end_col < 0)
945- extent->end_col = screen->cols;
946-
947- for(col = pos.col - 1; col >= extent->start_col; col--)
948- if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
949- break;
950- extent->start_col = col + 1;
951-
952- for(col = pos.col + 1; col < extent->end_col; col++)
953- if(attrs_differ(attrs, target, getcell(screen, pos.row, col)))
954- break;
955- extent->end_col = col - 1;
956-
957- return 1;
958-}
diff -r 4af19863e264 -r da6a7491e148 src/version.c
--- a/src/version.c Wed Oct 09 23:00:05 2019 +0200
+++ b/src/version.c Thu Oct 10 13:30:04 2019 +0200
@@ -754,6 +754,8 @@
754754 static int included_patches[] =
755755 { /* Add new patch number below this line */
756756 /**/
757+ 2128,
758+/**/
757759 2127,
758760 /**/
759761 2126,
Show on old repository browser