47
47
#define MOD_ALT 0x02
48
48
#define MOD_CTRL 0x04
50
#define ATTRMASK_BOLD 0x01
51
#define ATTRMASK_UNDERLINE 0x02
52
#define ATTRMASK_BLINK 0x04
53
#define ATTRMASK_INVERSE 0x08
54
#define ATTRMASK_CONCEALED 0x10
57
#define MAX_RESPONSE 11
61
#define MODE_SHOW_CURSOR 0x00000001
62
#define MODE_INVERSE 0x00000002
63
#define MODE_AUTOWRAP 0x00000004
64
#define MODE_AUTOREPEAT 0x00000008
65
#define MODE_LF_NEWLINE 0x00000010
66
#define MODE_IRM 0x00000020
67
#define MODE_DELETE_SENDS_DEL 0x00000040
68
#define MODE_ALT_SENDS_ESC 0x00000080
71
unsigned char byte[4];
84
struct utf8_state_machine {
85
enum utf8_state state;
91
init_state_machine(struct utf8_state_machine *machine)
93
machine->state = utf8state_start;
98
static enum utf8_state
99
utf8_next_char(struct utf8_state_machine *machine, char c)
101
switch(machine->state) {
102
case utf8state_start:
103
case utf8state_accept:
104
case utf8state_reject:
107
if(c == 0xC0 || c == 0xC1) {
108
/* overlong encoding, reject */
109
machine->state = utf8state_reject;
110
} else if((c & 0x80) == 0) {
111
/* single byte, accept */
112
machine->s.byte[machine->len++] = c;
113
machine->state = utf8state_accept;
114
} else if((c & 0xC0) == 0x80) {
115
/* parser out of sync, ignore byte */
116
machine->state = utf8state_start;
117
} else if((c & 0xE0) == 0xC0) {
118
/* start of two byte sequence */
119
machine->s.byte[machine->len++] = c;
120
machine->state = utf8state_expect1;
121
} else if((c & 0xF0) == 0xE0) {
122
/* start of three byte sequence */
123
machine->s.byte[machine->len++] = c;
124
machine->state = utf8state_expect2;
125
} else if((c & 0xF8) == 0xF0) {
126
/* start of four byte sequence */
127
machine->s.byte[machine->len++] = c;
128
machine->state = utf8state_expect3;
130
/* overlong encoding, reject */
131
machine->state = utf8state_reject;
134
case utf8state_expect3:
135
machine->s.byte[machine->len++] = c;
136
if((c & 0xC0) == 0x80) {
137
/* all good, continue */
138
machine->state = utf8state_expect2;
140
/* missing extra byte, reject */
141
machine->state = utf8state_reject;
144
case utf8state_expect2:
145
machine->s.byte[machine->len++] = c;
146
if((c & 0xC0) == 0x80) {
147
/* all good, continue */
148
machine->state = utf8state_expect1;
150
/* missing extra byte, reject */
151
machine->state = utf8state_reject;
154
case utf8state_expect1:
155
machine->s.byte[machine->len++] = c;
156
if((c & 0xC0) == 0x80) {
157
/* all good, accept */
158
machine->state = utf8state_accept;
160
/* missing extra byte, reject */
161
machine->state = utf8state_reject;
165
machine->state = utf8state_reject;
169
return machine->state;
173
union utf8_char match;
174
union utf8_char replace;
176
/* Set last char_sub match to NULL char */
177
typedef struct char_sub *character_set;
179
struct char_sub CS_US[] = {
182
static struct char_sub CS_UK[] = {
183
{{{'#', 0, }}, {{0xC2, 0xA3, 0, }}},
186
static struct char_sub CS_SPECIAL[] = {
187
{{{'`', 0, }}, {{0xE2, 0x99, 0xA6, 0}}}, /* diamond */
188
{{{'a', 0, }}, {{0xE2, 0x96, 0x92, 0}}}, /* 50% cell */
189
{{{'b', 0, }}, {{0xE2, 0x90, 0x89, 0}}}, /* HT */
190
{{{'c', 0, }}, {{0xE2, 0x90, 0x8C, 0}}}, /* FF */
191
{{{'d', 0, }}, {{0xE2, 0x90, 0x8D, 0}}}, /* CR */
192
{{{'e', 0, }}, {{0xE2, 0x90, 0x8A, 0}}}, /* LF */
193
{{{'f', 0, }}, {{0xC2, 0xB0, 0, }}}, /* Degree */
194
{{{'g', 0, }}, {{0xC2, 0xB1, 0, }}}, /* Plus/Minus */
195
{{{'h', 0, }}, {{0xE2, 0x90, 0xA4, 0}}}, /* NL */
196
{{{'i', 0, }}, {{0xE2, 0x90, 0x8B, 0}}}, /* VT */
197
{{{'j', 0, }}, {{0xE2, 0x94, 0x98, 0}}}, /* CN_RB */
198
{{{'k', 0, }}, {{0xE2, 0x94, 0x90, 0}}}, /* CN_RT */
199
{{{'l', 0, }}, {{0xE2, 0x94, 0x8C, 0}}}, /* CN_LT */
200
{{{'m', 0, }}, {{0xE2, 0x94, 0x94, 0}}}, /* CN_RB */
201
{{{'n', 0, }}, {{0xE2, 0x94, 0xBC, 0}}}, /* CROSS */
202
{{{'o', 0, }}, {{0xE2, 0x94, 0x80, 0}}}, /* H */
203
{{{'p', 0, }}, {{0xE2, 0x94, 0x80, 0}}}, /* H */
204
{{{'q', 0, }}, {{0xE2, 0x94, 0x80, 0}}}, /* H */
205
{{{'r', 0, }}, {{0xE2, 0x94, 0x80, 0}}}, /* H */
206
{{{'s', 0, }}, {{0xE2, 0x94, 0x80, 0}}}, /* H */
207
{{{'t', 0, }}, {{0xE2, 0x94, 0x9C, 0}}}, /* TR */
208
{{{'u', 0, }}, {{0xE2, 0x94, 0xA4, 0}}}, /* TL */
209
{{{'v', 0, }}, {{0xE2, 0x94, 0xB4, 0}}}, /* TU */
210
{{{'w', 0, }}, {{0xE2, 0x94, 0xAC, 0}}}, /* TD */
211
{{{'x', 0, }}, {{0xE2, 0x94, 0x82, 0}}}, /* V */
212
{{{'y', 0, }}, {{0xE2, 0x89, 0xA4, 0}}}, /* LE */
213
{{{'z', 0, }}, {{0xE2, 0x89, 0xA5, 0}}}, /* GE */
214
{{{'{', 0, }}, {{0xCF, 0x80, 0, }}}, /* PI */
215
{{{'|', 0, }}, {{0xE2, 0x89, 0xA0, 0}}}, /* NEQ */
216
{{{'}', 0, }}, {{0xC2, 0xA3, 0, }}}, /* POUND */
217
{{{'~', 0, }}, {{0xE2, 0x8B, 0x85, 0}}}, /* DOT */
222
apply_char_set(character_set cs, union utf8_char *utf8)
226
while (cs[i].match.byte[0]) {
227
if ((*utf8).ch == cs[i].match.ch) {
228
*utf8 = cs[i].replace;
241
/* Set last key_sub sym to NULL */
242
typedef struct key_map *keyboard_mode;
244
static struct key_map KM_NORMAL[] = {
245
{XK_Left, 1, '[', 'D'},
246
{XK_Right, 1, '[', 'C'},
247
{XK_Up, 1, '[', 'A'},
248
{XK_Down, 1, '[', 'B'},
249
{XK_Home, 1, '[', 'H'},
250
{XK_End, 1, '[', 'F'},
253
static struct key_map KM_APPLICATION[] = {
254
{XK_Left, 1, 'O', 'D'},
255
{XK_Right, 1, 'O', 'C'},
256
{XK_Up, 1, 'O', 'A'},
257
{XK_Down, 1, 'O', 'B'},
258
{XK_Home, 1, 'O', 'H'},
259
{XK_End, 1, 'O', 'F'},
260
{XK_KP_Enter, 1, 'O', 'M'},
261
{XK_KP_Multiply, 1, 'O', 'j'},
262
{XK_KP_Add, 1, 'O', 'k'},
263
{XK_KP_Separator, 1, 'O', 'l'},
264
{XK_KP_Subtract, 1, 'O', 'm'},
265
{XK_KP_Divide, 1, 'O', 'o'},
270
function_key_response(char escape, int num, uint32_t modifiers,
271
char code, char *response)
276
if (modifiers & WINDOW_MODIFIER_SHIFT) mod_num |= 1;
277
if (modifiers & WINDOW_MODIFIER_ALT) mod_num |= 2;
278
if (modifiers & WINDOW_MODIFIER_CONTROL) mod_num |= 4;
281
len = snprintf(response, MAX_RESPONSE, "\e[%d;%d%c",
282
num, mod_num + 1, code);
283
else if (code != '~')
284
len = snprintf(response, MAX_RESPONSE, "\e%c%c",
287
len = snprintf(response, MAX_RESPONSE, "\e%c%d%c",
290
if (len >= MAX_RESPONSE) return MAX_RESPONSE - 1;
294
/* returns the number of bytes written into response,
295
* which must have room for MAX_RESPONSE bytes */
297
apply_key_map(keyboard_mode mode, int sym, uint32_t modifiers, char *response)
303
while (mode[i].sym) {
305
if (sym == map.sym) {
306
len = function_key_response(map.escape, map.num,
316
struct terminal_color { double r, g, b, a; };
318
unsigned char fg, bg;
319
char a; /* attributes format:
322
char r; /* reserved */
324
struct color_scheme {
325
struct terminal_color palette[16];
327
struct attr default_attr;
331
attr_init(struct attr *data_attr, struct attr attr, int n)
334
for (i = 0; i < n; i++) {
340
escape_state_normal = 0,
345
escape_state_inner_escape,
350
#define ESC_FLAG_WHAT 0x01
351
#define ESC_FLAG_GT 0x02
352
#define ESC_FLAG_BANG 0x04
353
#define ESC_FLAG_CASH 0x08
354
#define ESC_FLAG_SQUOTE 0x10
355
#define ESC_FLAG_DQUOTE 0x20
356
#define ESC_FLAG_SPACE 0x40
51
359
struct window *window;
52
360
struct display *display;
361
union utf8_char *data;
363
struct attr *data_attr;
364
struct attr curr_attr;
367
char saved_origin_mode;
368
struct attr saved_attr;
369
union utf8_char last_char;
370
int margin_top, margin_bottom;
371
character_set cs, g0, g1;
372
character_set saved_cs, saved_g0, saved_g1;
373
keyboard_mode key_mode;
374
int data_pitch, attr_pitch; /* The width in bytes of a line */
54
375
int width, height, start, row, column;
376
int saved_row, saved_column;
56
378
GIOChannel *channel;
57
379
uint32_t modifiers;
380
char escape[MAX_ESCAPE];
59
381
int escape_length;
382
enum escape_state state;
383
enum escape_state outer_state;
385
struct utf8_state_machine state_machine;
64
389
struct color_scheme *color_scheme;
390
struct terminal_color color_table[256];
65
391
cairo_font_extents_t extents;
392
cairo_scaled_font_t *font_normal, *font_bold;
395
/* Create default tab stops, every 8 characters */
397
terminal_init_tabs(struct terminal *terminal)
401
while (i < terminal->width) {
403
terminal->tab_ruler[i] = 1;
405
terminal->tab_ruler[i] = 0;
411
terminal_init(struct terminal *terminal)
413
terminal->curr_attr = terminal->color_scheme->default_attr;
414
terminal->origin_mode = 0;
415
terminal->mode = MODE_SHOW_CURSOR |
421
terminal->column = 0;
423
terminal->g0 = CS_US;
424
terminal->g1 = CS_US;
425
terminal->cs = terminal->g0;
426
terminal->key_mode = KM_NORMAL;
428
terminal->saved_g0 = terminal->g0;
429
terminal->saved_g1 = terminal->g1;
430
terminal->saved_cs = terminal->cs;
432
terminal->saved_attr = terminal->curr_attr;
433
terminal->saved_origin_mode = terminal->origin_mode;
434
terminal->saved_row = terminal->row;
435
terminal->saved_column = terminal->column;
437
if (terminal->tab_ruler != NULL) terminal_init_tabs(terminal);
441
init_color_table(struct terminal *terminal)
444
struct terminal_color *color_table = terminal->color_table;
446
for (c = 0; c < 256; c ++) {
448
color_table[c] = terminal->color_scheme->palette[c];
449
} else if (c < 232) {
451
color_table[c].b = ((double)(r % 6) / 6.0); r /= 6;
452
color_table[c].g = ((double)(r % 6) / 6.0); r /= 6;
453
color_table[c].r = ((double)(r % 6) / 6.0);
454
color_table[c].a = 1.0;
456
r = (c - 232) * 10 + 8;
457
color_table[c].r = ((double) r) / 256.0;
458
color_table[c].g = color_table[c].r;
459
color_table[c].b = color_table[c].r;
460
color_table[c].a = 1.0;
465
static union utf8_char *
69
466
terminal_get_row(struct terminal *terminal, int row)
73
470
index = (row + terminal->start) % terminal->height;
75
return &terminal->data[index * (terminal->width + 1)];
472
return &terminal->data[index * terminal->width];
476
terminal_get_attr_row(struct terminal *terminal, int row)
480
index = (row + terminal->start) % terminal->height;
482
return &terminal->data_attr[index * terminal->width];
491
terminal_decode_attr(struct terminal *terminal, int row, int col,
492
union decoded_attr *decoded)
495
int foreground, background, tmp;
497
/* get the attributes for this character cell */
498
attr = terminal_get_attr_row(terminal, row)[col];
499
if ((attr.a & ATTRMASK_INVERSE) ||
500
((terminal->mode & MODE_SHOW_CURSOR) &&
501
terminal->focused && terminal->row == row &&
502
terminal->column == col)) {
503
foreground = attr.bg;
504
background = attr.fg;
505
if (attr.a & ATTRMASK_BOLD) {
506
if (foreground <= 16) foreground |= 0x08;
507
if (background <= 16) background &= 0x07;
510
foreground = attr.fg;
511
background = attr.bg;
514
if (terminal->mode & MODE_INVERSE) {
516
foreground = background;
518
if (attr.a & ATTRMASK_BOLD) {
519
if (foreground <= 16) foreground |= 0x08;
520
if (background <= 16) background &= 0x07;
524
decoded->attr.fg = foreground;
525
decoded->attr.bg = background;
526
decoded->attr.a = attr.a;
530
terminal_scroll_buffer(struct terminal *terminal, int d)
534
d = d % (terminal->height + 1);
535
terminal->start = (terminal->start + d) % terminal->height;
536
if (terminal->start < 0) terminal->start = terminal->height + terminal->start;
539
for(i = 0; i < d; i++) {
540
memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
541
attr_init(terminal_get_attr_row(terminal, i),
542
terminal->curr_attr, terminal->width);
545
for(i = terminal->height - d; i < terminal->height; i++) {
546
memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
547
attr_init(terminal_get_attr_row(terminal, i),
548
terminal->curr_attr, terminal->width);
554
terminal_scroll_window(struct terminal *terminal, int d)
558
int from_row, to_row;
560
// scrolling range is inclusive
561
window_height = terminal->margin_bottom - terminal->margin_top + 1;
562
d = d % (window_height + 1);
565
to_row = terminal->margin_bottom;
566
from_row = terminal->margin_bottom - d;
568
for (i = 0; i < (window_height - d); i++) {
569
memcpy(terminal_get_row(terminal, to_row - i),
570
terminal_get_row(terminal, from_row - i),
571
terminal->data_pitch);
572
memcpy(terminal_get_attr_row(terminal, to_row - i),
573
terminal_get_attr_row(terminal, from_row - i),
574
terminal->attr_pitch);
576
for (i = terminal->margin_top; i < (terminal->margin_top + d); i++) {
577
memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
578
attr_init(terminal_get_attr_row(terminal, i),
579
terminal->curr_attr, terminal->width);
582
to_row = terminal->margin_top;
583
from_row = terminal->margin_top + d;
585
for (i = 0; i < (window_height - d); i++) {
586
memcpy(terminal_get_row(terminal, to_row + i),
587
terminal_get_row(terminal, from_row + i),
588
terminal->data_pitch);
589
memcpy(terminal_get_attr_row(terminal, to_row + i),
590
terminal_get_attr_row(terminal, from_row + i),
591
terminal->attr_pitch);
593
for (i = terminal->margin_bottom - d + 1; i <= terminal->margin_bottom; i++) {
594
memset(terminal_get_row(terminal, i), 0, terminal->data_pitch);
595
attr_init(terminal_get_attr_row(terminal, i),
596
terminal->curr_attr, terminal->width);
602
terminal_scroll(struct terminal *terminal, int d)
604
if(terminal->margin_top == 0 && terminal->margin_bottom == terminal->height - 1)
605
terminal_scroll_buffer(terminal, d);
607
terminal_scroll_window(terminal, d);
611
terminal_shift_line(struct terminal *terminal, int d)
613
union utf8_char *row;
614
struct attr *attr_row, attr;
616
row = terminal_get_row(terminal, terminal->row);
617
attr_row = terminal_get_attr_row(terminal, terminal->row);
619
if ((terminal->width + d) <= terminal->column)
620
d = terminal->column + 1 - terminal->width;
621
if ((terminal->column + d) >= terminal->width)
622
d = terminal->width - terminal->column - 1;
626
memmove(&row[terminal->column],
627
&row[terminal->column + d],
628
(terminal->width - terminal->column - d) * sizeof(union utf8_char));
629
attr = attr_row[terminal->width - 1];
630
memmove(&attr_row[terminal->column], &attr_row[terminal->column + d],
631
(terminal->width - terminal->column - d) * sizeof(struct attr));
632
memset(&row[terminal->width - d], 0, d * sizeof(union utf8_char));
633
attr_init(&attr_row[terminal->width - d], terminal->curr_attr, d);
635
memmove(&row[terminal->column + d], &row[terminal->column],
636
(terminal->width - terminal->column - d) * sizeof(union utf8_char));
637
memmove(&attr_row[terminal->column + d], &attr_row[terminal->column],
638
(terminal->width - terminal->column - d) * sizeof(struct attr));
639
memset(&row[terminal->column], 0, d * sizeof(union utf8_char));
640
attr_init(&attr_row[terminal->column], terminal->curr_attr, d);
79
645
terminal_resize(struct terminal *terminal, int width, int height)
648
union utf8_char *data;
649
struct attr *data_attr;
651
int data_pitch, attr_pitch;
83
652
int i, l, total_rows, start;
653
struct rectangle allocation;
655
int32_t pixel_width, pixel_height;
85
661
if (terminal->width == width && terminal->height == height)
88
size = (width + 1) * height;
664
if (!terminal->fullscreen) {
665
pixel_width = width *
666
terminal->extents.max_x_advance + 2 * terminal->margin;
667
pixel_height = height *
668
terminal->extents.height + 2 * terminal->margin;
669
window_set_child_size(terminal->window,
670
pixel_width, pixel_height);
673
window_schedule_redraw (terminal->window);
675
data_pitch = width * sizeof(union utf8_char);
676
size = data_pitch * height;
89
677
data = malloc(size);
678
attr_pitch = width * sizeof(struct attr);
679
data_attr = malloc(attr_pitch * height);
680
tab_ruler = malloc(width);
90
681
memset(data, 0, size);
682
memset(tab_ruler, 0, width);
683
attr_init(data_attr, terminal->curr_attr, width * height);
684
if (terminal->data && terminal->data_attr) {
92
685
if (width > terminal->width)
93
686
l = terminal->width;
105
for (i = 0; i < total_rows; i++)
106
memcpy(data + (width + 1) * i,
107
terminal_get_row(terminal, i), l);
698
for (i = 0; i < total_rows; i++) {
699
memcpy(&data[width * i],
700
terminal_get_row(terminal, i),
701
l * sizeof(union utf8_char));
702
memcpy(&data_attr[width * i],
703
terminal_get_attr_row(terminal, i),
704
l * sizeof(struct attr));
109
707
free(terminal->data);
708
free(terminal->data_attr);
709
free(terminal->tab_ruler);
712
terminal->data_pitch = data_pitch;
713
terminal->attr_pitch = attr_pitch;
714
terminal->margin_bottom =
715
height - (terminal->height - terminal->margin_bottom);
112
716
terminal->width = width;
113
717
terminal->height = height;
114
718
terminal->data = data;
116
if (terminal->row >= terminal->height)
117
terminal->row = terminal->height - 1;
118
if (terminal->column >= terminal->width)
119
terminal->column = terminal->width - 1;
123
struct color_scheme { struct { double r, g, b, a; } fg, bg; }
124
matrix_colors = { { 0, 0.7, 0, 1 }, { 0, 0, 0, 0.9 } },
125
jbarnes_colors = { { 1, 1, 1, 1 }, { 0, 0, 0, 1 } };
719
terminal->data_attr = data_attr;
720
terminal->tab_ruler = tab_ruler;
721
terminal_init_tabs(terminal);
723
/* Update the window size */
724
ws.ws_row = terminal->height;
725
ws.ws_col = terminal->width;
726
window_get_child_allocation(terminal->window, &allocation);
727
ws.ws_xpixel = allocation.width;
728
ws.ws_ypixel = allocation.height;
729
ioctl(terminal->master, TIOCSWINSZ, &ws);
732
struct color_scheme DEFAULT_COLORS = {
734
{0, 0, 0, 1}, /* black */
735
{0.66, 0, 0, 1}, /* red */
736
{0 , 0.66, 0, 1}, /* green */
737
{0.66, 0.33, 0, 1}, /* orange (nicer than muddy yellow) */
738
{0 , 0 , 0.66, 1}, /* blue */
739
{0.66, 0 , 0.66, 1}, /* magenta */
740
{0, 0.66, 0.66, 1}, /* cyan */
741
{0.66, 0.66, 0.66, 1}, /* light grey */
742
{0.22, 0.33, 0.33, 1}, /* dark grey */
743
{1, 0.33, 0.33, 1}, /* high red */
744
{0.33, 1, 0.33, 1}, /* high green */
745
{1, 1, 0.33, 1}, /* high yellow */
746
{0.33, 0.33, 1, 1}, /* high blue */
747
{1, 0.33, 1, 1}, /* high magenta */
748
{0.33, 1, 1, 1}, /* high cyan */
749
{1, 1, 1, 1} /* white */
751
0, /* black border */
752
{7, 0, 0, } /* bg:black (0), fg:light gray (7) */
756
terminal_set_color(struct terminal *terminal, cairo_t *cr, int index)
758
cairo_set_source_rgba(cr,
759
terminal->color_table[index].r,
760
terminal->color_table[index].g,
761
terminal->color_table[index].b,
762
terminal->color_table[index].a);
766
struct terminal *terminal;
769
union decoded_attr attr;
770
cairo_glyph_t glyphs[256], *g;
774
glyph_run_init(struct glyph_run *run, struct terminal *terminal, cairo_t *cr)
776
run->terminal = terminal;
778
run->g = run->glyphs;
784
glyph_run_flush(struct glyph_run *run, union decoded_attr attr)
786
cairo_scaled_font_t *font;
788
if (run->count > ARRAY_LENGTH(run->glyphs) - 10 ||
789
(attr.key != run->attr.key)) {
790
if (run->attr.attr.a & (ATTRMASK_BOLD | ATTRMASK_BLINK))
791
font = run->terminal->font_bold;
793
font = run->terminal->font_normal;
794
cairo_set_scaled_font(run->cr, font);
795
terminal_set_color(run->terminal, run->cr,
798
if (!(run->attr.attr.a & ATTRMASK_CONCEALED))
799
cairo_show_glyphs (run->cr, run->glyphs, run->count);
800
run->g = run->glyphs;
807
glyph_run_add(struct glyph_run *run, int x, int y, union utf8_char *c)
810
cairo_scaled_font_t *font;
812
num_glyphs = ARRAY_LENGTH(run->glyphs) - run->count;
814
if (run->attr.attr.a & (ATTRMASK_BOLD | ATTRMASK_BLINK))
815
font = run->terminal->font_bold;
817
font = run->terminal->font_normal;
819
cairo_move_to(run->cr, x, y);
820
cairo_scaled_font_text_to_glyphs (font, x, y,
822
&run->g, &num_glyphs,
824
run->g += num_glyphs;
825
run->count += num_glyphs;
128
829
terminal_draw_contents(struct terminal *terminal)
130
struct rectangle rectangle;
831
struct rectangle allocation;
132
833
cairo_font_extents_t extents;
133
int i, top_margin, side_margin;
834
int top_margin, side_margin;
836
union utf8_char *p_row;
837
union decoded_attr attr;
134
839
cairo_surface_t *surface;
137
window_get_child_rectangle(terminal->window, &rectangle);
139
surface = display_create_surface(terminal->display, &rectangle);
841
struct glyph_run run;
843
window_get_child_allocation(terminal->window, &allocation);
845
surface = display_create_surface(terminal->display, &allocation);
140
846
cr = cairo_create(surface);
141
847
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
142
cairo_set_source_rgba(cr,
143
terminal->color_scheme->bg.r,
144
terminal->color_scheme->bg.g,
145
terminal->color_scheme->bg.b,
146
terminal->color_scheme->bg.a);
848
terminal_set_color(terminal, cr, terminal->color_scheme->border);
851
cairo_set_scaled_font(cr, terminal->font_normal);
853
cairo_font_extents(cr, &extents);
854
side_margin = (allocation.width - terminal->width * extents.max_x_advance) / 2;
855
top_margin = (allocation.height - terminal->height * extents.height) / 2;
857
cairo_set_line_width(cr, 1.0);
859
/* paint the background */
860
for (row = 0; row < terminal->height; row++) {
861
for (col = 0; col < terminal->width; col++) {
862
/* get the attributes for this character cell */
863
terminal_decode_attr(terminal, row, col, &attr);
865
if (attr.attr.bg == terminal->color_scheme->border)
868
terminal_set_color(terminal, cr, attr.attr.bg);
869
cairo_move_to(cr, side_margin + (col * extents.max_x_advance),
870
top_margin + (row * extents.height));
871
cairo_rel_line_to(cr, extents.max_x_advance, 0);
872
cairo_rel_line_to(cr, 0, extents.height);
873
cairo_rel_line_to(cr, -extents.max_x_advance, 0);
874
cairo_close_path(cr);
148
879
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
149
cairo_set_source_rgba(cr,
150
terminal->color_scheme->fg.r,
151
terminal->color_scheme->fg.g,
152
terminal->color_scheme->fg.b,
153
terminal->color_scheme->fg.a);
155
cairo_select_font_face (cr, "mono",
156
CAIRO_FONT_SLANT_NORMAL,
157
CAIRO_FONT_WEIGHT_NORMAL);
158
cairo_set_font_size(cr, 14);
160
cairo_font_extents(cr, &extents);
161
side_margin = (rectangle.width - terminal->width * extents.max_x_advance) / 2;
162
top_margin = (rectangle.height - terminal->height * extents.height) / 2;
164
for (i = 0; i < terminal->height; i++) {
165
cairo_move_to(cr, side_margin,
166
top_margin + extents.ascent + extents.height * i);
167
cairo_show_text(cr, terminal_get_row(terminal, i));
881
/* paint the foreground */
882
glyph_run_init(&run, terminal, cr);
883
for (row = 0; row < terminal->height; row++) {
884
p_row = terminal_get_row(terminal, row);
885
for (col = 0; col < terminal->width; col++) {
886
/* get the attributes for this character cell */
887
terminal_decode_attr(terminal, row, col, &attr);
889
glyph_run_flush(&run, attr);
891
text_x = side_margin + col * extents.max_x_advance;
892
text_y = top_margin + extents.ascent + row * extents.height;
893
if (attr.attr.a & ATTRMASK_UNDERLINE) {
894
terminal_set_color(terminal, cr, attr.attr.fg);
895
cairo_move_to(cr, text_x, (double)text_y + 1.5);
896
cairo_line_to(cr, text_x + extents.max_x_advance, (double) text_y + 1.5);
900
glyph_run_add(&run, text_x, text_y, &p_row[col]);
170
d = terminal->focused ? 0 : 0.5;
172
cairo_set_line_width(cr, 1);
173
cairo_move_to(cr, side_margin + terminal->column * extents.max_x_advance + d,
174
top_margin + terminal->row * extents.height + d);
175
cairo_rel_line_to(cr, extents.max_x_advance - 2 * d, 0);
176
cairo_rel_line_to(cr, 0, extents.height - 2 * d);
177
cairo_rel_line_to(cr, -extents.max_x_advance + 2 * d, 0);
178
cairo_close_path(cr);
180
if (terminal->focused)
905
glyph_run_flush(&run, attr);
907
if ((terminal->mode & MODE_SHOW_CURSOR) && !terminal->focused) {
910
cairo_set_line_width(cr, 1);
911
cairo_move_to(cr, side_margin + terminal->column * extents.max_x_advance + d,
912
top_margin + terminal->row * extents.height + d);
913
cairo_rel_line_to(cr, extents.max_x_advance - 2 * d, 0);
914
cairo_rel_line_to(cr, 0, extents.height - 2 * d);
915
cairo_rel_line_to(cr, -extents.max_x_advance + 2 * d, 0);
916
cairo_close_path(cr);
183
918
cairo_stroke(cr);
185
921
cairo_destroy(cr);
187
window_copy_surface(terminal->window,
923
window_copy_surface(terminal->window, &allocation, surface);
191
925
cairo_surface_destroy(surface);
195
terminal_draw(struct terminal *terminal)
929
resize_handler(struct window *window,
930
int32_t pixel_width, int32_t pixel_height, void *data)
197
struct rectangle rectangle;
932
struct terminal *terminal = data;
198
933
int32_t width, height;
200
window_get_child_rectangle(terminal->window, &rectangle);
202
width = (rectangle.width - 2 * terminal->margin) /
935
width = (pixel_width - 2 * terminal->margin) /
203
936
(int32_t) terminal->extents.max_x_advance;
204
height = (rectangle.height - 2 * terminal->margin) /
937
height = (pixel_height - 2 * terminal->margin) /
205
938
(int32_t) terminal->extents.height;
206
940
terminal_resize(terminal, width, height);
208
if (!terminal->fullscreen) {
209
rectangle.width = terminal->width *
210
terminal->extents.max_x_advance + 2 * terminal->margin;
211
rectangle.height = terminal->height *
212
terminal->extents.height + 2 * terminal->margin;
213
window_set_child_size(terminal->window, &rectangle);
944
terminal_draw(struct terminal *terminal)
216
946
window_draw(terminal->window);
217
947
terminal_draw_contents(terminal);
218
948
window_flush(terminal->window);
257
count = set[0] ? args[0] : 1;
258
if (terminal->row - count >= 0)
1092
count = set[0] ? args[0] : 1;
1093
if (count == 0) count = 1;
1094
terminal_shift_line(terminal, count);
1097
count = set[0] ? args[0] : 1;
1098
if (count == 0) count = 1;
1099
if (terminal->row - count >= terminal->margin_top)
259
1100
terminal->row -= count;
1102
terminal->row = terminal->margin_top;
264
1105
count = set[0] ? args[0] : 1;
265
if (terminal->row + count < terminal->height)
1106
if (count == 0) count = 1;
1107
if (terminal->row + count <= terminal->margin_bottom)
266
1108
terminal->row += count;
268
terminal->row = terminal->height;
1110
terminal->row = terminal->margin_bottom;
271
1113
count = set[0] ? args[0] : 1;
272
if (terminal->column + count < terminal->width)
1114
if (count == 0) count = 1;
1115
if ((terminal->column + count) < terminal->width)
273
1116
terminal->column += count;
275
terminal->column = terminal->width;
1118
terminal->column = terminal->width - 1;
278
1121
count = set[0] ? args[0] : 1;
279
if (terminal->column - count >= 0)
1122
if (count == 0) count = 1;
1123
if ((terminal->column - count) >= 0)
280
1124
terminal->column -= count;
282
1126
terminal->column = 0;
285
row = terminal_get_row(terminal, terminal->row);
286
memset(&row[terminal->column], 0, terminal->width - terminal->column);
287
for (i = terminal->row + 1; i < terminal->height; i++)
288
memset(terminal_get_row(terminal, i), 0, terminal->width);
292
terminal->column = args[0] - 1;
296
terminal->row = set[0] ? args[0] - 1 : 0;
297
terminal->column = set[1] ? args[1] - 1 : 0;
300
row = terminal_get_row(terminal, terminal->row);
301
memset(&row[terminal->column], 0, terminal->width - terminal->column);
304
/* color, blink, bold etc*/
307
if (strcmp(p, "?25l") == 0) {
309
} else if (strcmp(p, "?25h") == 0) {
1129
count = set[0] ? args[0] : 1;
1130
if (terminal->row + count <= terminal->margin_bottom)
1131
terminal->row += count;
1133
terminal->row = terminal->margin_bottom;
1134
terminal->column = 0;
1137
count = set[0] ? args[0] : 1;
1138
if (terminal->row - count >= terminal->margin_top)
1139
terminal->row -= count;
1141
terminal->row = terminal->margin_top;
1142
terminal->column = 0;
1145
y = set[0] ? args[0] : 1;
1146
y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y;
1148
terminal->column = y - 1;
1152
x = (set[1] ? args[1] : 1) - 1;
1154
(x >= terminal->width ? terminal->width - 1 : x);
1156
y = (set[0] ? args[0] : 1) - 1;
1157
if (terminal->origin_mode) {
1158
y += terminal->margin_top;
1159
y = y < terminal->margin_top ? terminal->margin_top :
1160
(y > terminal->margin_bottom ? terminal->margin_bottom : y);
1163
(y >= terminal->height ? terminal->height - 1 : y);
1167
terminal->column = x;
1170
count = set[0] ? args[0] : 1;
1171
if (count == 0) count = 1;
1172
while (count > 0 && terminal->column < terminal->width) {
1173
if (terminal->tab_ruler[terminal->column]) count--;
1179
row = terminal_get_row(terminal, terminal->row);
1180
attr_row = terminal_get_attr_row(terminal, terminal->row);
1181
if (!set[0] || args[0] == 0 || args[0] > 2) {
1182
memset(&row[terminal->column],
1183
0, (terminal->width - terminal->column) * sizeof(union utf8_char));
1184
attr_init(&attr_row[terminal->column],
1185
terminal->curr_attr, terminal->width - terminal->column);
1186
for (i = terminal->row + 1; i < terminal->height; i++) {
1187
memset(terminal_get_row(terminal, i),
1188
0, terminal->data_pitch);
1189
attr_init(terminal_get_attr_row(terminal, i),
1190
terminal->curr_attr, terminal->width);
1192
} else if (args[0] == 1) {
1193
memset(row, 0, (terminal->column+1) * sizeof(union utf8_char));
1194
attr_init(attr_row, terminal->curr_attr, terminal->column+1);
1195
for (i = 0; i < terminal->row; i++) {
1196
memset(terminal_get_row(terminal, i),
1197
0, terminal->data_pitch);
1198
attr_init(terminal_get_attr_row(terminal, i),
1199
terminal->curr_attr, terminal->width);
1201
} else if (args[0] == 2) {
1202
for (i = 0; i < terminal->height; i++) {
1203
memset(terminal_get_row(terminal, i),
1204
0, terminal->data_pitch);
1205
attr_init(terminal_get_attr_row(terminal, i),
1206
terminal->curr_attr, terminal->width);
1211
row = terminal_get_row(terminal, terminal->row);
1212
attr_row = terminal_get_attr_row(terminal, terminal->row);
1213
if (!set[0] || args[0] == 0 || args[0] > 2) {
1214
memset(&row[terminal->column], 0,
1215
(terminal->width - terminal->column) * sizeof(union utf8_char));
1216
attr_init(&attr_row[terminal->column], terminal->curr_attr,
1217
terminal->width - terminal->column);
1218
} else if (args[0] == 1) {
1219
memset(row, 0, (terminal->column+1) * sizeof(union utf8_char));
1220
attr_init(attr_row, terminal->curr_attr, terminal->column+1);
1221
} else if (args[0] == 2) {
1222
memset(row, 0, terminal->data_pitch);
1223
attr_init(attr_row, terminal->curr_attr, terminal->width);
1227
count = set[0] ? args[0] : 1;
1228
if (count == 0) count = 1;
1229
if (terminal->row >= terminal->margin_top &&
1230
terminal->row < terminal->margin_bottom)
1232
top = terminal->margin_top;
1233
terminal->margin_top = terminal->row;
1234
terminal_scroll(terminal, 0 - count);
1235
terminal->margin_top = top;
1236
} else if (terminal->row == terminal->margin_bottom) {
1237
memset(terminal_get_row(terminal, terminal->row),
1238
0, terminal->data_pitch);
1239
attr_init(terminal_get_attr_row(terminal, terminal->row),
1240
terminal->curr_attr, terminal->width);
1244
count = set[0] ? args[0] : 1;
1245
if (count == 0) count = 1;
1246
if (terminal->row >= terminal->margin_top &&
1247
terminal->row < terminal->margin_bottom)
1249
top = terminal->margin_top;
1250
terminal->margin_top = terminal->row;
1251
terminal_scroll(terminal, count);
1252
terminal->margin_top = top;
1253
} else if (terminal->row == terminal->margin_bottom) {
1254
memset(terminal_get_row(terminal, terminal->row),
1255
0, terminal->data_pitch);
1259
count = set[0] ? args[0] : 1;
1260
if (count == 0) count = 1;
1261
terminal_shift_line(terminal, 0 - count);
1264
terminal_scroll(terminal, set[0] ? args[0] : 1);
1267
terminal_scroll(terminal, 0 - (set[0] ? args[0] : 1));
1270
count = set[0] ? args[0] : 1;
1271
if (count == 0) count = 1;
1272
if ((terminal->column + count) > terminal->width)
1273
count = terminal->width - terminal->column;
1274
row = terminal_get_row(terminal, terminal->row);
1275
attr_row = terminal_get_attr_row(terminal, terminal->row);
1276
memset(&row[terminal->column], 0, count * sizeof(union utf8_char));
1277
attr_init(&attr_row[terminal->column], terminal->curr_attr, count);
1280
count = set[0] ? args[0] : 1;
1281
if (count == 0) count = 1;
1282
while (count > 0 && terminal->column >= 0) {
1283
if (terminal->tab_ruler[terminal->column]) count--;
1289
y = set[0] ? args[0] : 1;
1290
y = y <= 0 ? 1 : y > terminal->width ? terminal->width : y;
1292
terminal->column = y - 1;
1295
count = set[0] ? args[0] : 1;
1296
if (count == 0) count = 1;
1297
if (terminal->last_char.byte[0])
1298
for (i = 0; i < count; i++)
1299
handle_char(terminal, terminal->last_char);
1300
terminal->last_char.byte[0] = 0;
1302
case 'c': /* Primary DA */
1303
write(terminal->master, "\e[?6c", 5);
1306
x = set[0] ? args[0] : 1;
1307
x = x <= 0 ? 1 : x > terminal->height ? terminal->height : x;
1309
terminal->row = x - 1;
1312
if (!set[0] || args[0] == 0) {
1313
terminal->tab_ruler[terminal->column] = 0;
1314
} else if (args[0] == 3) {
1315
memset(terminal->tab_ruler, 0, terminal->width);
1319
for(i = 0; i < 10 && set[i]; i++) {
1320
handle_term_parameter(terminal, args[i], 1);
1324
for(i = 0; i < 10 && set[i]; i++) {
1325
handle_term_parameter(terminal, args[i], 0);
1329
for(i = 0; i < 10; i++) {
1330
if (i <= 7 && set[i] && set[i + 1] &&
1331
set[i + 2] && args[i + 1] == 5)
1333
if (args[i] == 38) {
1334
handle_sgr(terminal, args[i + 2] + 256);
1336
} else if (args[i] == 48) {
1337
handle_sgr(terminal, args[i + 2] + 512);
1342
handle_sgr(terminal, args[i]);
1344
handle_sgr(terminal, 0);
1352
i = set[0] ? args[0] : 0;
1353
if (i == 0 || i == 5) {
1354
write(terminal->master, "\e[0n", 4);
1355
} else if (i == 6) {
1356
snprintf(response, MAX_RESPONSE, "\e[%d;%dR",
1357
terminal->origin_mode ?
1358
terminal->row+terminal->margin_top : terminal->row+1,
1359
terminal->column+1);
1360
write(terminal->master, response, strlen(response));
1365
terminal->margin_top = 0;
1366
terminal->margin_bottom = terminal->height-1;
1368
terminal->column = 0;
1370
top = (set[0] ? args[0] : 1) - 1;
1372
(top >= terminal->height ? terminal->height - 1 : top);
1373
bottom = (set[1] ? args[1] : 1) - 1;
1374
bottom = bottom < 0 ? 0 :
1375
(bottom >= terminal->height ? terminal->height - 1 : bottom);
1377
terminal->margin_top = top;
1378
terminal->margin_bottom = bottom;
1380
terminal->margin_top = 0;
1381
terminal->margin_bottom = terminal->height-1;
1383
if(terminal->origin_mode)
1384
terminal->row = terminal->margin_top;
1387
terminal->column = 0;
1391
terminal->saved_row = terminal->row;
1392
terminal->saved_column = terminal->column;
1395
terminal->row = terminal->saved_row;
1396
terminal->column = terminal->saved_column;
314
terminal_data(terminal,
315
terminal->escape + 1,
316
terminal->escape_length - 2);
1399
fprintf(stderr, "Unknown CSI escape: %c\n", *p);
1405
handle_non_csi_escape(struct terminal *terminal, char code)
1410
if(terminal->row < terminal->margin_top) {
1411
terminal->row = terminal->margin_top;
1412
terminal_scroll(terminal, -1);
1416
terminal->column = 0;
1420
if(terminal->row > terminal->margin_bottom) {
1421
terminal->row = terminal->margin_bottom;
1422
terminal_scroll(terminal, +1);
1426
terminal_init(terminal);
1429
terminal->tab_ruler[terminal->column] = 1;
1431
case '7': /* DECSC */
1432
terminal->saved_row = terminal->row;
1433
terminal->saved_column = terminal->column;
1434
terminal->saved_attr = terminal->curr_attr;
1435
terminal->saved_origin_mode = terminal->origin_mode;
1436
terminal->saved_cs = terminal->cs;
1437
terminal->saved_g0 = terminal->g0;
1438
terminal->saved_g1 = terminal->g1;
1440
case '8': /* DECRC */
1441
terminal->row = terminal->saved_row;
1442
terminal->column = terminal->saved_column;
1443
terminal->curr_attr = terminal->saved_attr;
1444
terminal->origin_mode = terminal->saved_origin_mode;
1445
terminal->cs = terminal->saved_cs;
1446
terminal->g0 = terminal->saved_g0;
1447
terminal->g1 = terminal->saved_g1;
1449
case '=': /* DECPAM */
1450
terminal->key_mode = KM_APPLICATION;
1452
case '>': /* DECPNM */
1453
terminal->key_mode = KM_NORMAL;
1456
fprintf(stderr, "Unknown escape code: %c\n", code);
1462
handle_special_escape(struct terminal *terminal, char special, char code)
1466
if (special == '#') {
1469
/* fill with 'E', no cheap way to do this */
1470
memset(terminal->data, 0, terminal->data_pitch * terminal->height);
1471
numChars = terminal->width * terminal->height;
1472
for(i = 0; i < numChars; i++) {
1473
terminal->data[i].byte[0] = 'E';
1477
fprintf(stderr, "Unknown HASH escape #%c\n", code);
1480
} else if (special == '(' || special == ')') {
1484
terminal->g0 = CS_SPECIAL;
1486
terminal->g1 = CS_SPECIAL;
1490
terminal->g0 = CS_UK;
1492
terminal->g1 = CS_UK;
1496
terminal->g0 = CS_US;
1498
terminal->g1 = CS_US;
1501
fprintf(stderr, "Unknown character set %c\n", code);
1505
fprintf(stderr, "Unknown special escape %c%c\n", special, code);
1510
handle_sgr(struct terminal *terminal, int code)
1514
terminal->curr_attr = terminal->color_scheme->default_attr;
1517
terminal->curr_attr.a |= ATTRMASK_BOLD;
1518
if (terminal->curr_attr.fg < 8)
1519
terminal->curr_attr.fg += 8;
1522
terminal->curr_attr.a |= ATTRMASK_UNDERLINE;
1525
terminal->curr_attr.a |= ATTRMASK_BLINK;
1528
terminal->curr_attr.a |= ATTRMASK_CONCEALED;
1533
terminal->curr_attr.a &= ~ATTRMASK_BOLD;
1534
if (terminal->curr_attr.fg < 16 && terminal->curr_attr.fg >= 8)
1535
terminal->curr_attr.fg -= 8;
1538
terminal->curr_attr.a &= ~ATTRMASK_UNDERLINE;
1541
terminal->curr_attr.a &= ~ATTRMASK_BLINK;
1545
terminal->curr_attr.a |= ATTRMASK_INVERSE;
1548
terminal->curr_attr.a &= ~ATTRMASK_INVERSE;
1551
terminal->curr_attr.a &= ~ATTRMASK_CONCEALED;
1554
terminal->curr_attr.fg = terminal->color_scheme->default_attr.fg;
1557
terminal->curr_attr.bg = terminal->color_scheme->default_attr.bg;
1560
if(code >= 30 && code <= 37) {
1561
terminal->curr_attr.fg = code - 30;
1562
if (terminal->curr_attr.a & ATTRMASK_BOLD)
1563
terminal->curr_attr.fg += 8;
1564
} else if(code >= 40 && code <= 47) {
1565
terminal->curr_attr.bg = code - 40;
1566
} else if (code >= 90 && code <= 97) {
1567
terminal->curr_attr.fg = code - 90 + 8;
1568
} else if (code >= 100 && code <= 107) {
1569
terminal->curr_attr.bg = code - 100 + 8;
1570
} else if(code >= 256 && code < 512) {
1571
terminal->curr_attr.fg = code - 256;
1572
} else if(code >= 512 && code < 768) {
1573
terminal->curr_attr.bg = code - 512;
1575
fprintf(stderr, "Unknown SGR code: %d\n", code);
1581
/* Returns 1 if c was special, otherwise 0 */
1583
handle_special_char(struct terminal *terminal, char c)
1585
union utf8_char *row;
1586
struct attr *attr_row;
1588
row = terminal_get_row(terminal, terminal->row);
1589
attr_row = terminal_get_attr_row(terminal, terminal->row);
1593
terminal->column = 0;
1596
if (terminal->mode & MODE_LF_NEWLINE) {
1597
terminal->column = 0;
1603
if(terminal->row > terminal->margin_bottom) {
1604
terminal->row = terminal->margin_bottom;
1605
terminal_scroll(terminal, +1);
1610
while (terminal->column < terminal->width) {
1611
if (terminal->tab_ruler[terminal->column]) break;
1612
if (terminal->mode & MODE_IRM)
1613
terminal_shift_line(terminal, +1);
1614
row[terminal->column].byte[0] = ' ';
1615
row[terminal->column].byte[1] = '\0';
1616
attr_row[terminal->column] = terminal->curr_attr;
1619
if (terminal->column >= terminal->width) {
1620
terminal->column = terminal->width - 1;
1625
if (terminal->column >= terminal->width) {
1626
terminal->column = terminal->width - 2;
1627
} else if (terminal->column > 0) {
1629
} else if (terminal->mode & MODE_AUTOWRAP) {
1630
terminal->column = terminal->width - 1;
1632
if (terminal->row < terminal->margin_top) {
1633
terminal->row = terminal->margin_top;
1634
terminal_scroll(terminal, -1);
1642
case '\x0E': /* SO */
1643
terminal->cs = terminal->g1;
1645
case '\x0F': /* SI */
1646
terminal->cs = terminal->g0;
1656
handle_char(struct terminal *terminal, union utf8_char utf8)
1658
union utf8_char *row;
1659
struct attr *attr_row;
1661
if (handle_special_char(terminal, utf8.byte[0])) return;
1663
apply_char_set(terminal->cs, &utf8);
1665
/* There are a whole lot of non-characters, control codes,
1666
* and formatting codes that should probably be ignored,
1668
if (strncmp((char*) utf8.byte, "\xEF\xBB\xBF", 3) == 0) {
1673
/* Some of these non-characters should be translated, e.g.: */
1674
if (utf8.byte[0] < 32) {
1675
utf8.byte[0] = utf8.byte[0] + 64;
1678
/* handle right margin effects */
1679
if (terminal->column >= terminal->width) {
1680
if (terminal->mode & MODE_AUTOWRAP) {
1681
terminal->column = 0;
1683
if (terminal->row > terminal->margin_bottom) {
1684
terminal->row = terminal->margin_bottom;
1685
terminal_scroll(terminal, +1);
1692
row = terminal_get_row(terminal, terminal->row);
1693
attr_row = terminal_get_attr_row(terminal, terminal->row);
1695
if (terminal->mode & MODE_IRM)
1696
terminal_shift_line(terminal, +1);
1697
row[terminal->column] = utf8;
1698
attr_row[terminal->column++] = terminal->curr_attr;
1700
if (utf8.ch != terminal->last_char.ch)
1701
terminal->last_char = utf8;
1705
escape_append_utf8(struct terminal *terminal, union utf8_char utf8)
1709
if ((utf8.byte[0] & 0x80) == 0x00) len = 1;
1710
else if ((utf8.byte[0] & 0xE0) == 0xC0) len = 2;
1711
else if ((utf8.byte[0] & 0xF0) == 0xE0) len = 3;
1712
else if ((utf8.byte[0] & 0xF8) == 0xF0) len = 4;
1713
else len = 1; /* Invalid, cannot happen */
1715
if (terminal->escape_length + len <= MAX_ESCAPE) {
1716
for (i = 0; i < len; i++)
1717
terminal->escape[terminal->escape_length + i] = utf8.byte[i];
1718
terminal->escape_length += len;
1719
} else if (terminal->escape_length < MAX_ESCAPE) {
1720
terminal->escape[terminal->escape_length++] = 0;
322
1725
terminal_data(struct terminal *terminal, const char *data, size_t length)
1728
union utf8_char utf8;
1729
enum utf8_state parser_state;
327
1731
for (i = 0; i < length; i++) {
328
row = terminal_get_row(terminal, terminal->row);
330
if (terminal->state == STATE_ESCAPE) {
331
terminal->escape[terminal->escape_length++] = data[i];
332
if (terminal->escape_length == 2 && data[i] != '[') {
333
/* Bad escape sequence. */
334
terminal->state = STATE_NORMAL;
338
if (isalpha(data[i])) {
339
terminal->state = STATE_NORMAL;
1733
utf8_next_char(&terminal->state_machine, data[i]);
1734
switch(parser_state) {
1735
case utf8state_accept:
1736
utf8.ch = terminal->state_machine.s.ch;
1738
case utf8state_reject:
1739
/* the unicode replacement character */
1740
utf8.byte[0] = 0xEF;
1741
utf8.byte[1] = 0xBF;
1742
utf8.byte[2] = 0xBD;
1743
utf8.byte[3] = 0x00;
1749
/* assume escape codes never use non-ASCII characters */
1750
switch (terminal->state) {
1751
case escape_state_escape:
1752
escape_append_utf8(terminal, utf8);
1753
switch (utf8.byte[0]) {
1755
terminal->state = escape_state_dcs;
1758
terminal->state = escape_state_csi;
1761
terminal->state = escape_state_osc;
1765
case ')': /* special */
1766
terminal->state = escape_state_special;
1768
case '^': /* PM (not implemented) */
1769
case '_': /* APC (not implemented) */
1770
terminal->state = escape_state_ignore;
1773
terminal->state = escape_state_normal;
1774
handle_non_csi_escape(terminal, utf8.byte[0]);
1778
case escape_state_csi:
1779
if (handle_special_char(terminal, utf8.byte[0]) != 0) {
1781
} else if (utf8.byte[0] == '?') {
1782
terminal->escape_flags |= ESC_FLAG_WHAT;
1783
} else if (utf8.byte[0] == '>') {
1784
terminal->escape_flags |= ESC_FLAG_GT;
1785
} else if (utf8.byte[0] == '!') {
1786
terminal->escape_flags |= ESC_FLAG_BANG;
1787
} else if (utf8.byte[0] == '$') {
1788
terminal->escape_flags |= ESC_FLAG_CASH;
1789
} else if (utf8.byte[0] == '\'') {
1790
terminal->escape_flags |= ESC_FLAG_SQUOTE;
1791
} else if (utf8.byte[0] == '"') {
1792
terminal->escape_flags |= ESC_FLAG_DQUOTE;
1793
} else if (utf8.byte[0] == ' ') {
1794
terminal->escape_flags |= ESC_FLAG_SPACE;
1796
escape_append_utf8(terminal, utf8);
1797
if (terminal->escape_length >= MAX_ESCAPE)
1798
terminal->state = escape_state_normal;
1801
if (isalpha(utf8.byte[0]) || utf8.byte[0] == '@' ||
1802
utf8.byte[0] == '`')
1804
terminal->state = escape_state_normal;
340
1805
handle_escape(terminal);
1809
case escape_state_inner_escape:
1810
if (utf8.byte[0] == '\\') {
1811
terminal->state = escape_state_normal;
1812
if (terminal->outer_state == escape_state_dcs) {
1813
handle_dcs(terminal);
1814
} else if (terminal->outer_state == escape_state_osc) {
1815
handle_osc(terminal);
1817
} else if (utf8.byte[0] == '\e') {
1818
terminal->state = terminal->outer_state;
1819
escape_append_utf8(terminal, utf8);
1820
if (terminal->escape_length >= MAX_ESCAPE)
1821
terminal->state = escape_state_normal;
1823
terminal->state = terminal->outer_state;
1824
if (terminal->escape_length < MAX_ESCAPE)
1825
terminal->escape[terminal->escape_length++] = '\e';
1826
escape_append_utf8(terminal, utf8);
1827
if (terminal->escape_length >= MAX_ESCAPE)
1828
terminal->state = escape_state_normal;
1831
case escape_state_dcs:
1832
case escape_state_osc:
1833
case escape_state_ignore:
1834
if (utf8.byte[0] == '\e') {
1835
terminal->outer_state = terminal->state;
1836
terminal->state = escape_state_inner_escape;
1837
} else if (utf8.byte[0] == '\a' && terminal->state == escape_state_osc) {
1838
terminal->state = escape_state_normal;
1839
handle_osc(terminal);
1841
escape_append_utf8(terminal, utf8);
1842
if (terminal->escape_length >= MAX_ESCAPE)
1843
terminal->state = escape_state_normal;
1846
case escape_state_special:
1847
escape_append_utf8(terminal, utf8);
1848
terminal->state = escape_state_normal;
1849
if (isdigit(utf8.byte[0]) || isalpha(utf8.byte[0])) {
1850
handle_special_escape(terminal, terminal->escape[1],
348
terminal->column = 0;
351
terminal->column = 0;
352
if (terminal->row + 1 < terminal->height) {
356
if (terminal->start == terminal->height)
358
memset(terminal_get_row(terminal, terminal->row),
364
memset(&row[terminal->column], ' ', -terminal->column & 7);
365
terminal->column = (terminal->column + 7) & ~7;
368
terminal->state = STATE_ESCAPE;
1858
/* this is valid, because ASCII characters are never used to
1859
* introduce a multibyte sequence in UTF-8 */
1860
if (utf8.byte[0] == '\e') {
1861
terminal->state = escape_state_escape;
1862
terminal->outer_state = escape_state_normal;
369
1863
terminal->escape[0] = '\e';
370
1864
terminal->escape_length = 1;
373
if (terminal->column > 0)
380
if (terminal->column < terminal->width)
381
row[terminal->column++] = data[i] < 32 ? data[i] + 64 : data[i];
1865
terminal->escape_flags = 0;
1867
handle_char(terminal, utf8);
386
1871
window_schedule_redraw(terminal->window);