1 /*
2 * Copyright (C) 2001-2004 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19
20 #include <config.h>
21
22 #include <limits.h>
23 #ifdef HAVE_SYS_SYSLIMITS_H
24 #include <sys/syslimits.h>
25 #endif
26
27 #include <glib.h>
28
29 #include "vte.h"
30 #include "vte-private.h"
31
32 #define BEL "\007"
33 #define ST _VTE_CAP_ST
34
35 /* FUNCTIONS WE USE */
36
37 static void
display_control_sequence(const char * name,GValueArray * params)38 display_control_sequence(const char *name, GValueArray *params)
39 {
40 #ifdef VTE_DEBUG
41 guint i;
42 long l;
43 const char *s;
44 const gunichar *w;
45 GValue *value;
46 g_printerr("%s(", name);
47 if (params != NULL) {
48 for (i = 0; i < params->n_values; i++) {
49 value = g_value_array_get_nth(params, i);
50 if (i > 0) {
51 g_printerr(", ");
52 }
53 if (G_VALUE_HOLDS_LONG(value)) {
54 l = g_value_get_long(value);
55 g_printerr("%ld", l);
56 } else
57 if (G_VALUE_HOLDS_STRING(value)) {
58 s = g_value_get_string(value);
59 g_printerr("\"%s\"", s);
60 } else
61 if (G_VALUE_HOLDS_POINTER(value)) {
62 w = g_value_get_pointer(value);
63 g_printerr("\"%ls\"", (const wchar_t*) w);
64 }
65 }
66 }
67 g_printerr(")\n");
68 #endif
69 }
70
71
72 /* A couple are duplicated from vte.c, to keep them static... */
73
74 /* Check how long a string of unichars is. Slow version. */
75 static gssize
vte_unichar_strlen(gunichar * c)76 vte_unichar_strlen(gunichar *c)
77 {
78 int i;
79 for (i = 0; c[i] != 0; i++) ;
80 return i;
81 }
82
83 /* Convert a wide character string to a multibyte string */
84 static gchar *
vte_ucs4_to_utf8(VteTerminal * terminal,const guchar * in)85 vte_ucs4_to_utf8 (VteTerminal *terminal, const guchar *in)
86 {
87 gchar *out = NULL;
88 guchar *buf = NULL, *bufptr = NULL;
89 gsize inlen, outlen;
90 VteConv conv;
91
92 conv = _vte_conv_open ("UTF-8", VTE_CONV_GUNICHAR_TYPE);
93
94 if (conv != VTE_INVALID_CONV) {
95 inlen = vte_unichar_strlen ((gunichar *) in) * sizeof (gunichar);
96 outlen = (inlen * VTE_UTF8_BPC) + 1;
97
98 _vte_byte_array_set_minimum_size (terminal->pvt->conv_buffer, outlen);
99 buf = bufptr = terminal->pvt->conv_buffer->data;
100
101 if (_vte_conv (conv, &in, &inlen, &buf, &outlen) == (size_t) -1) {
102 _vte_debug_print (VTE_DEBUG_IO,
103 "Error converting %ld string bytes (%s), skipping.\n",
104 (long) _vte_byte_array_length (terminal->pvt->outgoing),
105 g_strerror (errno));
106 bufptr = NULL;
107 } else {
108 out = g_strndup ((gchar *) bufptr, buf - bufptr);
109 }
110 }
111
112 _vte_conv_close (conv);
113
114 return out;
115 }
116
117 static gboolean
vte_parse_color(const char * spec,PangoColor * color)118 vte_parse_color (const char *spec, PangoColor *color)
119 {
120 gchar *spec_copy = (gchar *) spec;
121 gboolean retval = FALSE;
122 GdkColor gdk_color;
123
124 /* gdk_color_parse doesnt handle all XParseColor formats. It only
125 * supports the #RRRGGGBBB format, not the rgb:RRR/GGG/BBB format.
126 * See: man XParseColor */
127
128 if (g_ascii_strncasecmp (spec_copy, "rgb:", 4) == 0) {
129 gchar *cur, *ptr;
130
131 spec_copy = g_strdup (spec);
132 cur = spec_copy;
133 ptr = spec_copy + 3;
134
135 *cur++ = '#';
136 while (*ptr++)
137 if (*ptr != '/')
138 *cur++ = *ptr;
139 *cur++ = '\0';
140 }
141
142 retval = gdk_color_parse (spec_copy, &gdk_color);
143
144 if (spec_copy != spec)
145 g_free (spec_copy);
146
147 if (retval) {
148 color->red = gdk_color.red;
149 color->green = gdk_color.green;
150 color->blue = gdk_color.blue;
151 }
152
153 return retval;
154 }
155
156
157
158
159
160
161 /* Emit a "deiconify-window" signal. */
162 static void
vte_terminal_emit_deiconify_window(VteTerminal * terminal)163 vte_terminal_emit_deiconify_window(VteTerminal *terminal)
164 {
165 _vte_debug_print(VTE_DEBUG_SIGNALS,
166 "Emitting `deiconify-window'.\n");
167 g_signal_emit_by_name(terminal, "deiconify-window");
168 }
169
170 /* Emit a "iconify-window" signal. */
171 static void
vte_terminal_emit_iconify_window(VteTerminal * terminal)172 vte_terminal_emit_iconify_window(VteTerminal *terminal)
173 {
174 _vte_debug_print(VTE_DEBUG_SIGNALS,
175 "Emitting `iconify-window'.\n");
176 g_signal_emit_by_name(terminal, "iconify-window");
177 }
178
179 /* Emit a "raise-window" signal. */
180 static void
vte_terminal_emit_raise_window(VteTerminal * terminal)181 vte_terminal_emit_raise_window(VteTerminal *terminal)
182 {
183 _vte_debug_print(VTE_DEBUG_SIGNALS,
184 "Emitting `raise-window'.\n");
185 g_signal_emit_by_name(terminal, "raise-window");
186 }
187
188 /* Emit a "lower-window" signal. */
189 static void
vte_terminal_emit_lower_window(VteTerminal * terminal)190 vte_terminal_emit_lower_window(VteTerminal *terminal)
191 {
192 _vte_debug_print(VTE_DEBUG_SIGNALS,
193 "Emitting `lower-window'.\n");
194 g_signal_emit_by_name(terminal, "lower-window");
195 }
196
197 /* Emit a "maximize-window" signal. */
198 static void
vte_terminal_emit_maximize_window(VteTerminal * terminal)199 vte_terminal_emit_maximize_window(VteTerminal *terminal)
200 {
201 _vte_debug_print(VTE_DEBUG_SIGNALS,
202 "Emitting `maximize-window'.\n");
203 g_signal_emit_by_name(terminal, "maximize-window");
204 }
205
206 /* Emit a "refresh-window" signal. */
207 static void
vte_terminal_emit_refresh_window(VteTerminal * terminal)208 vte_terminal_emit_refresh_window(VteTerminal *terminal)
209 {
210 _vte_debug_print(VTE_DEBUG_SIGNALS,
211 "Emitting `refresh-window'.\n");
212 g_signal_emit_by_name(terminal, "refresh-window");
213 }
214
215 /* Emit a "restore-window" signal. */
216 static void
vte_terminal_emit_restore_window(VteTerminal * terminal)217 vte_terminal_emit_restore_window(VteTerminal *terminal)
218 {
219 _vte_debug_print(VTE_DEBUG_SIGNALS,
220 "Emitting `restore-window'.\n");
221 g_signal_emit_by_name(terminal, "restore-window");
222 }
223
224 /* Emit a "move-window" signal. (Pixels.) */
225 static void
vte_terminal_emit_move_window(VteTerminal * terminal,guint x,guint y)226 vte_terminal_emit_move_window(VteTerminal *terminal, guint x, guint y)
227 {
228 _vte_debug_print(VTE_DEBUG_SIGNALS,
229 "Emitting `move-window'.\n");
230 g_signal_emit_by_name(terminal, "move-window", x, y);
231 }
232
233 /* Emit a "resize-window" signal. (Grid size.) */
234 static void
vte_terminal_emit_resize_window(VteTerminal * terminal,guint columns,guint rows)235 vte_terminal_emit_resize_window(VteTerminal *terminal,
236 guint columns, guint rows)
237 {
238 _vte_debug_print(VTE_DEBUG_SIGNALS,
239 "Emitting `resize-window'.\n");
240 g_signal_emit_by_name(terminal, "resize-window", columns, rows);
241 }
242
243
244 /* Some common functions */
245
246 /* In Xterm, upon printing a character in the last column the cursor doesn't
247 * advance. It's special cased that printing the following letter will first
248 * wrap to the next row.
249 *
250 * As a rule of thumb, escape sequences that move the cursor (e.g. cursor up)
251 * or immediately update the visible contents (e.g. clear in line) disable
252 * this special mode, whereas escape sequences with no immediate visible
253 * effect (e.g. color change) leave this special mode on. There are
254 * exceptions of course (e.g. scroll up).
255 *
256 * In VTE, a different technical approach is used. The cursor is advanced to
257 * the invisible column on the right, but it's set back to the visible
258 * rightmost column whenever necessary (that is, before handling any of the
259 * sequences that disable the special cased mode in xterm). (Bug 731155.)
260 */
261 static void
_vte_terminal_ensure_cursor_is_onscreen(VteTerminal * terminal)262 _vte_terminal_ensure_cursor_is_onscreen (VteTerminal *terminal)
263 {
264 if (G_UNLIKELY (terminal->pvt->cursor.col >= terminal->pvt->column_count))
265 terminal->pvt->cursor.col = terminal->pvt->column_count - 1;
266 }
267
268 static void
_vte_terminal_home_cursor(VteTerminal * terminal)269 _vte_terminal_home_cursor (VteTerminal *terminal)
270 {
271 long origin;
272 VteScreen *screen;
273 screen = terminal->pvt->screen;
274
275 if (terminal->pvt->origin_mode &&
276 terminal->pvt->scrolling_restricted) {
277 origin = terminal->pvt->scrolling_region.start;
278 } else {
279 origin = 0;
280 }
281
282 terminal->pvt->cursor.row = screen->insert_delta + origin;
283 terminal->pvt->cursor.col = 0;
284 }
285
286 /* Clear the entire screen. */
287 static void
_vte_terminal_clear_screen(VteTerminal * terminal)288 _vte_terminal_clear_screen (VteTerminal *terminal)
289 {
290 long i, initial, row;
291 VteScreen *screen;
292 screen = terminal->pvt->screen;
293 initial = screen->insert_delta;
294 row = terminal->pvt->cursor.row - screen->insert_delta;
295 initial = _vte_ring_next(screen->row_data);
296 /* Add a new screen's worth of rows. */
297 for (i = 0; i < terminal->pvt->row_count; i++)
298 _vte_terminal_ring_append (terminal, TRUE);
299 /* Move the cursor and insertion delta to the first line in the
300 * newly-cleared area and scroll if need be. */
301 screen->insert_delta = initial;
302 terminal->pvt->cursor.row = row + screen->insert_delta;
303 _vte_terminal_adjust_adjustments(terminal);
304 /* Redraw everything. */
305 _vte_invalidate_all(terminal);
306 /* We've modified the display. Make a note of it. */
307 terminal->pvt->text_deleted_flag = TRUE;
308 }
309
310 /* Clear the current line. */
311 static void
_vte_terminal_clear_current_line(VteTerminal * terminal)312 _vte_terminal_clear_current_line (VteTerminal *terminal)
313 {
314 VteRowData *rowdata;
315 VteScreen *screen;
316
317 screen = terminal->pvt->screen;
318
319 /* If the cursor is actually on the screen, clear data in the row
320 * which corresponds to the cursor. */
321 if (_vte_ring_next(screen->row_data) > terminal->pvt->cursor.row) {
322 /* Get the data for the row which the cursor points to. */
323 rowdata = _vte_ring_index_writable (screen->row_data, terminal->pvt->cursor.row);
324 g_assert(rowdata != NULL);
325 /* Remove it. */
326 _vte_row_data_shrink (rowdata, 0);
327 /* Add enough cells to the end of the line to fill out the row. */
328 _vte_row_data_fill (rowdata, &terminal->pvt->fill_defaults, terminal->pvt->column_count);
329 rowdata->attr.soft_wrapped = 0;
330 /* Repaint this row. */
331 _vte_invalidate_cells(terminal,
332 0, terminal->pvt->column_count,
333 terminal->pvt->cursor.row, 1);
334 }
335
336 /* We've modified the display. Make a note of it. */
337 terminal->pvt->text_deleted_flag = TRUE;
338 }
339
340 /* Clear above the current line. */
341 static void
_vte_terminal_clear_above_current(VteTerminal * terminal)342 _vte_terminal_clear_above_current (VteTerminal *terminal)
343 {
344 VteRowData *rowdata;
345 long i;
346 VteScreen *screen;
347 screen = terminal->pvt->screen;
348 /* If the cursor is actually on the screen, clear data in the row
349 * which corresponds to the cursor. */
350 for (i = screen->insert_delta; i < terminal->pvt->cursor.row; i++) {
351 if (_vte_ring_next(screen->row_data) > i) {
352 /* Get the data for the row we're erasing. */
353 rowdata = _vte_ring_index_writable (screen->row_data, i);
354 g_assert(rowdata != NULL);
355 /* Remove it. */
356 _vte_row_data_shrink (rowdata, 0);
357 /* Add new cells until we fill the row. */
358 _vte_row_data_fill (rowdata, &terminal->pvt->fill_defaults, terminal->pvt->column_count);
359 rowdata->attr.soft_wrapped = 0;
360 /* Repaint the row. */
361 _vte_invalidate_cells(terminal,
362 0, terminal->pvt->column_count, i, 1);
363 }
364 }
365 /* We've modified the display. Make a note of it. */
366 terminal->pvt->text_deleted_flag = TRUE;
367 }
368
369 /* Scroll the text, but don't move the cursor. Negative = up, positive = down. */
370 static void
_vte_terminal_scroll_text(VteTerminal * terminal,int scroll_amount)371 _vte_terminal_scroll_text (VteTerminal *terminal, int scroll_amount)
372 {
373 long start, end, i;
374 VteScreen *screen;
375
376 screen = terminal->pvt->screen;
377
378 if (terminal->pvt->scrolling_restricted) {
379 start = screen->insert_delta + terminal->pvt->scrolling_region.start;
380 end = screen->insert_delta + terminal->pvt->scrolling_region.end;
381 } else {
382 start = screen->insert_delta;
383 end = start + terminal->pvt->row_count - 1;
384 }
385
386 while (_vte_ring_next(screen->row_data) <= end)
387 _vte_terminal_ring_append (terminal, FALSE);
388
389 if (scroll_amount > 0) {
390 for (i = 0; i < scroll_amount; i++) {
391 _vte_terminal_ring_remove (terminal, end);
392 _vte_terminal_ring_insert (terminal, start, TRUE);
393 }
394 } else {
395 for (i = 0; i < -scroll_amount; i++) {
396 _vte_terminal_ring_remove (terminal, start);
397 _vte_terminal_ring_insert (terminal, end, TRUE);
398 }
399 }
400
401 /* Update the display. */
402 _vte_terminal_scroll_region(terminal, start, end - start + 1,
403 scroll_amount);
404
405 /* Adjust the scrollbars if necessary. */
406 _vte_terminal_adjust_adjustments(terminal);
407
408 /* We've modified the display. Make a note of it. */
409 terminal->pvt->text_inserted_flag = TRUE;
410 terminal->pvt->text_deleted_flag = TRUE;
411 }
412
413 /* Restore cursor. */
414 static void
vte_sequence_handler_restore_cursor(VteTerminal * terminal,GValueArray * params)415 vte_sequence_handler_restore_cursor (VteTerminal *terminal, GValueArray *params)
416 {
417 _vte_terminal_restore_cursor(terminal, terminal->pvt->screen);
418 _vte_terminal_ensure_cursor_is_onscreen(terminal);
419 }
420
421 /* Save cursor. */
422 static void
vte_sequence_handler_save_cursor(VteTerminal * terminal,GValueArray * params)423 vte_sequence_handler_save_cursor (VteTerminal *terminal, GValueArray *params)
424 {
425 _vte_terminal_save_cursor(terminal, terminal->pvt->screen);
426 }
427
428 /* Switch to normal screen. */
429 static void
vte_sequence_handler_normal_screen(VteTerminal * terminal,GValueArray * params)430 vte_sequence_handler_normal_screen (VteTerminal *terminal, GValueArray *params)
431 {
432 /* cursor.row includes insert_delta, adjust accordingly */
433 terminal->pvt->cursor.row -= terminal->pvt->screen->insert_delta;
434 terminal->pvt->screen = &terminal->pvt->normal_screen;
435 terminal->pvt->cursor.row += terminal->pvt->screen->insert_delta;
436
437 /* Make sure the ring is large enough */
438 _vte_terminal_ensure_row(terminal);
439 }
440
441 /* Switch to alternate screen. */
442 static void
vte_sequence_handler_alternate_screen(VteTerminal * terminal,GValueArray * params)443 vte_sequence_handler_alternate_screen (VteTerminal *terminal, GValueArray *params)
444 {
445 /* cursor.row includes insert_delta, adjust accordingly */
446 terminal->pvt->cursor.row -= terminal->pvt->screen->insert_delta;
447 terminal->pvt->screen = &terminal->pvt->alternate_screen;
448 terminal->pvt->cursor.row += terminal->pvt->screen->insert_delta;
449
450 /* Make sure the ring is large enough */
451 _vte_terminal_ensure_row(terminal);
452 }
453
454 /* Switch to normal screen and restore cursor (in this order). */
455 static void
vte_sequence_handler_normal_screen_and_restore_cursor(VteTerminal * terminal,GValueArray * params)456 vte_sequence_handler_normal_screen_and_restore_cursor (VteTerminal *terminal, GValueArray *params)
457 {
458 vte_sequence_handler_normal_screen (terminal, params);
459 vte_sequence_handler_restore_cursor (terminal, params);
460 }
461
462 /* Save cursor and switch to alternate screen (in this order). */
463 static void
vte_sequence_handler_save_cursor_and_alternate_screen(VteTerminal * terminal,GValueArray * params)464 vte_sequence_handler_save_cursor_and_alternate_screen (VteTerminal *terminal, GValueArray *params)
465 {
466 vte_sequence_handler_save_cursor (terminal, params);
467 vte_sequence_handler_alternate_screen (terminal, params);
468 }
469
470 /* Set icon/window titles. */
471 static void
vte_sequence_handler_set_title_internal(VteTerminal * terminal,GValueArray * params,gboolean icon_title,gboolean window_title)472 vte_sequence_handler_set_title_internal(VteTerminal *terminal,
473 GValueArray *params,
474 gboolean icon_title,
475 gboolean window_title)
476 {
477 GValue *value;
478 char *title = NULL;
479
480 if (icon_title == FALSE && window_title == FALSE)
481 return;
482
483 /* Get the string parameter's value. */
484 value = g_value_array_get_nth(params, 0);
485 if (value) {
486 if (G_VALUE_HOLDS_LONG(value)) {
487 /* Convert the long to a string. */
488 title = g_strdup_printf("%ld", g_value_get_long(value));
489 } else
490 if (G_VALUE_HOLDS_STRING(value)) {
491 /* Copy the string into the buffer. */
492 title = g_value_dup_string(value);
493 } else
494 if (G_VALUE_HOLDS_POINTER(value)) {
495 title = vte_ucs4_to_utf8 (terminal, g_value_get_pointer (value));
496 }
497 if (title != NULL) {
498 char *p, *validated;
499 const char *end;
500
501 /* Validate the text. */
502 g_utf8_validate(title, strlen(title), &end);
503 validated = g_strndup(title, end - title);
504
505 /* No control characters allowed. */
506 for (p = validated; *p != '\0'; p++) {
507 if ((*p & 0x1f) == *p) {
508 *p = ' ';
509 }
510 }
511
512 /* Emit the signal */
513 if (window_title) {
514 g_free (terminal->pvt->window_title_changed);
515 terminal->pvt->window_title_changed = g_strdup (validated);
516 }
517
518 if (icon_title) {
519 g_free (terminal->pvt->icon_title_changed);
520 terminal->pvt->icon_title_changed = g_strdup (validated);
521 }
522
523 g_free (validated);
524 g_free(title);
525 }
526 }
527 }
528
529 /* Toggle a terminal mode. */
530 static void
vte_sequence_handler_set_mode_internal(VteTerminal * terminal,long setting,gboolean value)531 vte_sequence_handler_set_mode_internal(VteTerminal *terminal,
532 long setting, gboolean value)
533 {
534 switch (setting) {
535 case 2: /* keyboard action mode (?) */
536 break;
537 case 4: /* insert/overtype mode */
538 terminal->pvt->insert_mode = value;
539 break;
540 case 12: /* send/receive mode (local echo) */
541 terminal->pvt->sendrecv_mode = value;
542 break;
543 case 20: /* automatic newline / normal linefeed mode */
544 terminal->pvt->linefeed_mode = value;
545 break;
546 default:
547 break;
548 }
549 }
550
551
552 /*
553 * Sequence handling boilerplate
554 */
555
556 /* Typedef the handle type */
557 typedef void (*VteTerminalSequenceHandler) (VteTerminal *terminal, GValueArray *params);
558
559 /* Prototype all handlers... */
560 #define VTE_SEQUENCE_HANDLER(name) \
561 static void name (VteTerminal *terminal, GValueArray *params);
562 #include "vteseq-list.h"
563 #undef VTE_SEQUENCE_HANDLER
564
565
566 /* Call another function a given number of times, or once. */
567 static void
vte_sequence_handler_multiple_limited(VteTerminal * terminal,GValueArray * params,VteTerminalSequenceHandler handler,glong max)568 vte_sequence_handler_multiple_limited(VteTerminal *terminal,
569 GValueArray *params,
570 VteTerminalSequenceHandler handler,
571 glong max)
572 {
573 long val = 1;
574 int i;
575 GValue *value;
576
577 if ((params != NULL) && (params->n_values > 0)) {
578 value = g_value_array_get_nth(params, 0);
579 if (G_VALUE_HOLDS_LONG(value)) {
580 val = g_value_get_long(value);
581 val = CLAMP(val, 1, max); /* FIXME: vttest. */
582 }
583 }
584 for (i = 0; i < val; i++)
585 handler (terminal, NULL);
586 }
587
588 static void
vte_sequence_handler_multiple_r(VteTerminal * terminal,GValueArray * params,VteTerminalSequenceHandler handler)589 vte_sequence_handler_multiple_r(VteTerminal *terminal,
590 GValueArray *params,
591 VteTerminalSequenceHandler handler)
592 {
593 vte_sequence_handler_multiple_limited(terminal, params, handler,
594 terminal->pvt->column_count - terminal->pvt->cursor.col);
595 }
596
597 static void
vte_reset_mouse_smooth_scroll_delta(VteTerminal * terminal,GValueArray * params)598 vte_reset_mouse_smooth_scroll_delta(VteTerminal *terminal,
599 GValueArray *params)
600 {
601 terminal->pvt->mouse_smooth_scroll_delta = 0.;
602 }
603
604 struct decset_t {
605 gint16 setting;
606 /* offset in VteTerminalPrivate (> 0) or VteScreen (< 0) */
607 gint16 boffset;
608 gint16 ioffset;
609 gint16 poffset;
610 gint16 fvalue;
611 gint16 tvalue;
612 VteTerminalSequenceHandler reset, set;
613 };
614
615 static int
decset_cmp(const void * va,const void * vb)616 decset_cmp(const void *va,
617 const void *vb)
618 {
619 const struct decset_t *a = va;
620 const struct decset_t *b = vb;
621
622 return a->setting < b->setting ? -1 : a->setting > b->setting;
623 }
624
625 /* Manipulate certain terminal attributes. */
626 static void
vte_sequence_handler_decset_internal(VteTerminal * terminal,int setting,gboolean restore,gboolean save,gboolean set)627 vte_sequence_handler_decset_internal(VteTerminal *terminal,
628 int setting,
629 gboolean restore,
630 gboolean save,
631 gboolean set)
632 {
633 static const struct decset_t const settings[] = {
634 #define PRIV_OFFSET(member) (G_STRUCT_OFFSET(VteTerminalPrivate, member))
635 #define SCREEN_OFFSET(member) (-G_STRUCT_OFFSET(VteScreen, member))
636 /* 1: Application/normal cursor keys. */
637 {1, 0, PRIV_OFFSET(cursor_mode), 0,
638 VTE_KEYMODE_NORMAL,
639 VTE_KEYMODE_APPLICATION,
640 NULL, NULL,},
641 /* 2: disallowed, we don't do VT52. */
642 {2, 0, 0, 0, 0, 0, NULL, NULL,},
643 /* 3: DECCOLM set/reset to and from 132/80 columns */
644 {3, 0, 0, 0,
645 FALSE,
646 TRUE,
647 NULL, NULL,},
648 /* 5: Reverse video. */
649 {5, PRIV_OFFSET(reverse_mode), 0, 0,
650 FALSE,
651 TRUE,
652 NULL, NULL,},
653 /* 6: Origin mode: when enabled, cursor positioning is
654 * relative to the scrolling region. */
655 {6, PRIV_OFFSET(origin_mode), 0, 0,
656 FALSE,
657 TRUE,
658 NULL, NULL,},
659 /* 7: Wraparound mode. */
660 {7, PRIV_OFFSET(autowrap), 0, 0,
661 FALSE,
662 TRUE,
663 NULL, NULL,},
664 /* 8: disallowed, keyboard repeat is set by user. */
665 {8, 0, 0, 0, 0, 0, NULL, NULL,},
666 /* 9: Send-coords-on-click. */
667 {9, 0, PRIV_OFFSET(mouse_tracking_mode), 0,
668 0,
669 MOUSE_TRACKING_SEND_XY_ON_CLICK,
670 vte_reset_mouse_smooth_scroll_delta,
671 vte_reset_mouse_smooth_scroll_delta,},
672 /* 12: disallowed, cursor blinks is set by user. */
673 {12, 0, 0, 0, 0, 0, NULL, NULL,},
674 /* 18: print form feed. */
675 /* 19: set print extent to full screen. */
676 /* 25: Cursor visible. */
677 {25, PRIV_OFFSET(cursor_visible), 0, 0,
678 FALSE,
679 TRUE,
680 NULL, NULL,},
681 /* 30/rxvt: disallowed, scrollbar visibility is set by user. */
682 {30, 0, 0, 0, 0, 0, NULL, NULL,},
683 /* 35/rxvt: disallowed, fonts set by user. */
684 {35, 0, 0, 0, 0, 0, NULL, NULL,},
685 /* 38: enter Tektronix mode. */
686 /* 40: Enable DECCOLM mode. */
687 {40, PRIV_OFFSET(deccolm_mode), 0, 0,
688 FALSE,
689 TRUE,
690 NULL, NULL,},
691 /* 41: more(1) fix. */
692 /* 42: Enable NLS replacements. */
693 /* 44: Margin bell. */
694 {44, PRIV_OFFSET(margin_bell), 0, 0,
695 FALSE,
696 TRUE,
697 NULL, NULL,},
698 /* 47: Alternate screen. */
699 {47, 0, 0, 0,
700 0,
701 0,
702 vte_sequence_handler_normal_screen,
703 vte_sequence_handler_alternate_screen,},
704 /* 66: Keypad mode. */
705 {66, PRIV_OFFSET(keypad_mode), 0, 0,
706 VTE_KEYMODE_NORMAL,
707 VTE_KEYMODE_APPLICATION,
708 NULL, NULL,},
709 /* 67: disallowed, backspace key policy is set by user. */
710 {67, 0, 0, 0, 0, 0, NULL, NULL,},
711 /* 1000: Send-coords-on-button. */
712 {1000, 0, PRIV_OFFSET(mouse_tracking_mode), 0,
713 0,
714 MOUSE_TRACKING_SEND_XY_ON_BUTTON,
715 vte_reset_mouse_smooth_scroll_delta,
716 vte_reset_mouse_smooth_scroll_delta,},
717 /* 1001: Hilite tracking. */
718 {1001, 0, PRIV_OFFSET(mouse_tracking_mode), 0,
719 (0),
720 (MOUSE_TRACKING_HILITE_TRACKING),
721 vte_reset_mouse_smooth_scroll_delta,
722 vte_reset_mouse_smooth_scroll_delta,},
723 /* 1002: Cell motion tracking. */
724 {1002, 0, PRIV_OFFSET(mouse_tracking_mode), 0,
725 (0),
726 (MOUSE_TRACKING_CELL_MOTION_TRACKING),
727 vte_reset_mouse_smooth_scroll_delta,
728 vte_reset_mouse_smooth_scroll_delta,},
729 /* 1003: All motion tracking. */
730 {1003, 0, PRIV_OFFSET(mouse_tracking_mode), 0,
731 (0),
732 (MOUSE_TRACKING_ALL_MOTION_TRACKING),
733 vte_reset_mouse_smooth_scroll_delta,
734 vte_reset_mouse_smooth_scroll_delta,},
735 /* 1006: Extended mouse coordinates. */
736 {1006, PRIV_OFFSET(mouse_xterm_extension), 0, 0,
737 FALSE,
738 TRUE,
739 NULL, NULL,},
740 /* 1007: Alternate screen scroll. */
741 {1007, PRIV_OFFSET(alternate_screen_scroll), 0, 0,
742 FALSE,
743 TRUE,
744 NULL, NULL,},
745 /* 1010/rxvt: disallowed, scroll-on-output is set by user. */
746 {1010, 0, 0, 0, 0, 0, NULL, NULL,},
747 /* 1011/rxvt: disallowed, scroll-on-keypress is set by user. */
748 {1011, 0, 0, 0, 0, 0, NULL, NULL,},
749 /* 1015/urxvt: Extended mouse coordinates. */
750 {1015, PRIV_OFFSET(mouse_urxvt_extension), 0, 0,
751 FALSE,
752 TRUE,
753 NULL, NULL,},
754 /* 1035: disallowed, don't know what to do with it. */
755 {1035, 0, 0, 0, 0, 0, NULL, NULL,},
756 /* 1036: Meta-sends-escape. */
757 {1036, PRIV_OFFSET(meta_sends_escape), 0, 0,
758 FALSE,
759 TRUE,
760 NULL, NULL,},
761 /* 1037: disallowed, delete key policy is set by user. */
762 {1037, 0, 0, 0, 0, 0, NULL, NULL,},
763 /* 1047: Use alternate screen buffer. */
764 {1047, 0, 0, 0,
765 0,
766 0,
767 vte_sequence_handler_normal_screen,
768 vte_sequence_handler_alternate_screen,},
769 /* 1048: Save/restore cursor position. */
770 {1048, 0, 0, 0,
771 0,
772 0,
773 vte_sequence_handler_restore_cursor,
774 vte_sequence_handler_save_cursor,},
775 /* 1049: Use alternate screen buffer, saving the cursor
776 * position. */
777 {1049, 0, 0, 0,
778 0,
779 0,
780 vte_sequence_handler_normal_screen_and_restore_cursor,
781 vte_sequence_handler_save_cursor_and_alternate_screen,},
782 /* 2004: Bracketed paste mode. */
783 {2004, PRIV_OFFSET(bracketed_paste_mode), 0, 0,
784 FALSE,
785 TRUE,
786 NULL, NULL,},
787 #undef PRIV_OFFSET
788 #undef SCREEN_OFFSET
789 };
790 struct decset_t key;
791 struct decset_t *found;
792
793 /* Handle the setting. */
794 key.setting = setting;
795 found = bsearch(&key, settings, G_N_ELEMENTS(settings), sizeof(settings[0]), decset_cmp);
796 if (!found) {
797 _vte_debug_print (VTE_DEBUG_MISC,
798 "DECSET/DECRESET mode %d not recognized, ignoring.\n",
799 setting);
800 return;
801 }
802
803 key = *found;
804 do {
805 gboolean *bvalue = NULL;
806 gint *ivalue = NULL;
807 gpointer *pvalue = NULL, pfvalue = NULL, ptvalue = NULL;
808 gpointer p;
809
810 /* Handle settings we want to ignore. */
811 if ((key.fvalue == key.tvalue) &&
812 (key.set == NULL) &&
813 (key.reset == NULL)) {
814 break;
815 }
816
817 #define STRUCT_MEMBER_P(type,total_offset) \
818 (type) (total_offset >= 0 ? G_STRUCT_MEMBER_P(terminal->pvt, total_offset) : G_STRUCT_MEMBER_P(terminal->pvt->screen, -total_offset))
819
820 if (key.boffset) {
821 bvalue = STRUCT_MEMBER_P(gboolean*, key.boffset);
822 } else if (key.ioffset) {
823 ivalue = STRUCT_MEMBER_P(int*, key.ioffset);
824 } else if (key.poffset) {
825 pvalue = STRUCT_MEMBER_P(gpointer*, key.poffset);
826 pfvalue = STRUCT_MEMBER_P(gpointer, key.fvalue);
827 ptvalue = STRUCT_MEMBER_P(gpointer, key.tvalue);
828 }
829 #undef STRUCT_MEMBER_P
830
831 /* Read the old setting. */
832 if (restore) {
833 p = g_hash_table_lookup(terminal->pvt->dec_saved,
834 GINT_TO_POINTER(setting));
835 set = (p != NULL);
836 _vte_debug_print(VTE_DEBUG_PARSE,
837 "Setting %d was %s.\n",
838 setting, set ? "set" : "unset");
839 }
840 /* Save the current setting. */
841 if (save) {
842 if (bvalue) {
843 set = *(bvalue) != FALSE;
844 } else
845 if (ivalue) {
846 set = *(ivalue) == (int)key.tvalue;
847 } else
848 if (pvalue) {
849 set = *(pvalue) == ptvalue;
850 }
851 _vte_debug_print(VTE_DEBUG_PARSE,
852 "Setting %d is %s, saving.\n",
853 setting, set ? "set" : "unset");
854 g_hash_table_insert(terminal->pvt->dec_saved,
855 GINT_TO_POINTER(setting),
856 GINT_TO_POINTER(set));
857 }
858 /* Change the current setting to match the new/saved value. */
859 if (!save) {
860 _vte_debug_print(VTE_DEBUG_PARSE,
861 "Setting %d to %s.\n",
862 setting, set ? "set" : "unset");
863 if (key.set && set) {
864 key.set (terminal, NULL);
865 }
866 if (bvalue) {
867 *(bvalue) = set;
868 } else
869 if (ivalue) {
870 *(ivalue) = set ? (int)key.tvalue : (int)key.fvalue;
871 } else
872 if (pvalue) {
873 *(pvalue) = set ? ptvalue : pfvalue;
874 }
875 if (key.reset && !set) {
876 key.reset (terminal, NULL);
877 }
878 }
879 } while (0);
880
881 /* Do whatever's necessary when the setting changes. */
882 switch (setting) {
883 case 1:
884 _vte_debug_print(VTE_DEBUG_KEYBOARD, set ?
885 "Entering application cursor mode.\n" :
886 "Leaving application cursor mode.\n");
887 break;
888 case 3:
889 /* 3: DECCOLM set/reset to 132/80 columns mode, clear screen and cursor home */
890 if (terminal->pvt->deccolm_mode) {
891 vte_terminal_emit_resize_window(terminal,
892 set ? 132 : 80,
893 terminal->pvt->row_count);
894 _vte_terminal_clear_screen(terminal);
895 _vte_terminal_home_cursor(terminal);
896 }
897 break;
898 case 5:
899 /* Repaint everything in reverse mode. */
900 _vte_invalidate_all(terminal);
901 break;
902 case 6:
903 /* Reposition the cursor in its new home position. */
904 _vte_terminal_home_cursor (terminal);
905 break;
906 case 47:
907 case 1047:
908 case 1049:
909 /* Clear the alternate screen if we're switching to it */
910 if (set) {
911 _vte_terminal_clear_screen (terminal);
912 }
913 /* Reset scrollbars and repaint everything. */
914 gtk_adjustment_set_value(terminal->pvt->vadjustment,
915 terminal->pvt->screen->scroll_delta);
916 vte_terminal_set_scrollback_lines(terminal,
917 terminal->pvt->scrollback_lines);
918 _vte_terminal_queue_contents_changed(terminal);
919 _vte_invalidate_all (terminal);
920 break;
921 case 9:
922 case 1000:
923 case 1001:
924 case 1002:
925 case 1003:
926 /* Make the pointer visible. */
927 _vte_terminal_set_pointer_visible(terminal, TRUE);
928 break;
929 case 66:
930 _vte_debug_print(VTE_DEBUG_KEYBOARD, set ?
931 "Entering application keypad mode.\n" :
932 "Leaving application keypad mode.\n");
933 break;
934 default:
935 break;
936 }
937 }
938
939
940
941
942 /* THE HANDLERS */
943
944
945 /* Do nothing. */
946 static void
vte_sequence_handler_nop(VteTerminal * terminal,GValueArray * params)947 vte_sequence_handler_nop (VteTerminal *terminal, GValueArray *params)
948 {
949 }
950
951 /* G0 character set is a pass-thru (no mapping). */
952 static void
vte_sequence_handler_designate_g0_plain(VteTerminal * terminal,GValueArray * params)953 vte_sequence_handler_designate_g0_plain (VteTerminal *terminal, GValueArray *params)
954 {
955 terminal->pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_NONE;
956 }
957
958 /* G0 character set is DEC Special Character and Line Drawing Set. */
959 static void
vte_sequence_handler_designate_g0_line_drawing(VteTerminal * terminal,GValueArray * params)960 vte_sequence_handler_designate_g0_line_drawing (VteTerminal *terminal, GValueArray *params)
961 {
962 terminal->pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_LINE_DRAWING;
963 }
964
965 /* G0 character set is British (# is converted to £). */
966 static void
vte_sequence_handler_designate_g0_british(VteTerminal * terminal,GValueArray * params)967 vte_sequence_handler_designate_g0_british (VteTerminal *terminal, GValueArray *params)
968 {
969 terminal->pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_BRITISH;
970 }
971
972 /* G1 character set is a pass-thru (no mapping). */
973 static void
vte_sequence_handler_designate_g1_plain(VteTerminal * terminal,GValueArray * params)974 vte_sequence_handler_designate_g1_plain (VteTerminal *terminal, GValueArray *params)
975 {
976 terminal->pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_NONE;
977 }
978
979 /* G1 character set is DEC Special Character and Line Drawing Set. */
980 static void
vte_sequence_handler_designate_g1_line_drawing(VteTerminal * terminal,GValueArray * params)981 vte_sequence_handler_designate_g1_line_drawing (VteTerminal *terminal, GValueArray *params)
982 {
983 terminal->pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_LINE_DRAWING;
984 }
985
986 /* G1 character set is British (# is converted to £). */
987 static void
vte_sequence_handler_designate_g1_british(VteTerminal * terminal,GValueArray * params)988 vte_sequence_handler_designate_g1_british (VteTerminal *terminal, GValueArray *params)
989 {
990 terminal->pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_BRITISH;
991 }
992
993 /* SI (shift in): switch to G0 character set. */
994 static void
vte_sequence_handler_shift_in(VteTerminal * terminal,GValueArray * params)995 vte_sequence_handler_shift_in (VteTerminal *terminal, GValueArray *params)
996 {
997 terminal->pvt->character_replacement = &terminal->pvt->character_replacements[0];
998 }
999
1000 /* SO (shift out): switch to G1 character set. */
1001 static void
vte_sequence_handler_shift_out(VteTerminal * terminal,GValueArray * params)1002 vte_sequence_handler_shift_out (VteTerminal *terminal, GValueArray *params)
1003 {
1004 terminal->pvt->character_replacement = &terminal->pvt->character_replacements[1];
1005 }
1006
1007 /* Beep. */
1008 static void
vte_sequence_handler_bell(VteTerminal * terminal,GValueArray * params)1009 vte_sequence_handler_bell (VteTerminal *terminal, GValueArray *params)
1010 {
1011 _vte_terminal_beep (terminal);
1012 g_signal_emit_by_name(terminal, "bell");
1013 }
1014
1015 /* Backtab. */
1016 static void
vte_sequence_handler_cursor_back_tab(VteTerminal * terminal,GValueArray * params)1017 vte_sequence_handler_cursor_back_tab (VteTerminal *terminal, GValueArray *params)
1018 {
1019 long newcol;
1020
1021 /* Calculate which column is the previous tab stop. */
1022 newcol = terminal->pvt->cursor.col;
1023
1024 if (terminal->pvt->tabstops != NULL) {
1025 /* Find the next tabstop. */
1026 while (newcol > 0) {
1027 newcol--;
1028 if (_vte_terminal_get_tabstop(terminal,
1029 newcol % terminal->pvt->column_count)) {
1030 break;
1031 }
1032 }
1033 }
1034
1035 /* Warp the cursor. */
1036 _vte_debug_print(VTE_DEBUG_PARSE,
1037 "Moving cursor to column %ld.\n", (long)newcol);
1038 terminal->pvt->cursor.col = newcol;
1039 }
1040
1041 /* Clear from the cursor position (inclusive!) to the beginning of the line. */
1042 static void
_vte_sequence_handler_cb(VteTerminal * terminal,GValueArray * params)1043 _vte_sequence_handler_cb (VteTerminal *terminal, GValueArray *params)
1044 {
1045 VteRowData *rowdata;
1046 long i;
1047 VteCell *pcell;
1048
1049 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1050
1051 /* Get the data for the row which the cursor points to. */
1052 rowdata = _vte_terminal_ensure_row(terminal);
1053 /* Clean up Tab/CJK fragments. */
1054 _vte_terminal_cleanup_fragments (terminal, 0, terminal->pvt->cursor.col + 1);
1055 /* Clear the data up to the current column with the default
1056 * attributes. If there is no such character cell, we need
1057 * to add one. */
1058 for (i = 0; i <= terminal->pvt->cursor.col; i++) {
1059 if (i < (glong) _vte_row_data_length (rowdata)) {
1060 /* Muck with the cell in this location. */
1061 pcell = _vte_row_data_get_writable (rowdata, i);
1062 *pcell = terminal->pvt->color_defaults;
1063 } else {
1064 /* Add new cells until we have one here. */
1065 _vte_row_data_append (rowdata, &terminal->pvt->color_defaults);
1066 }
1067 }
1068 /* Repaint this row. */
1069 _vte_invalidate_cells(terminal,
1070 0, terminal->pvt->cursor.col+1,
1071 terminal->pvt->cursor.row, 1);
1072
1073 /* We've modified the display. Make a note of it. */
1074 terminal->pvt->text_deleted_flag = TRUE;
1075 }
1076
1077 /* Clear to the right of the cursor and below the current line. */
1078 static void
_vte_sequence_handler_cd(VteTerminal * terminal,GValueArray * params)1079 _vte_sequence_handler_cd (VteTerminal *terminal, GValueArray *params)
1080 {
1081 VteRowData *rowdata;
1082 glong i;
1083 VteScreen *screen;
1084
1085 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1086
1087 screen = terminal->pvt->screen;
1088 /* If the cursor is actually on the screen, clear the rest of the
1089 * row the cursor is on and all of the rows below the cursor. */
1090 i = terminal->pvt->cursor.row;
1091 if (i < _vte_ring_next(screen->row_data)) {
1092 /* Get the data for the row we're clipping. */
1093 rowdata = _vte_ring_index_writable (screen->row_data, i);
1094 /* Clean up Tab/CJK fragments. */
1095 if ((glong) _vte_row_data_length (rowdata) > terminal->pvt->cursor.col)
1096 _vte_terminal_cleanup_fragments (terminal, terminal->pvt->cursor.col, _vte_row_data_length (rowdata));
1097 /* Clear everything to the right of the cursor. */
1098 if (rowdata)
1099 _vte_row_data_shrink (rowdata, terminal->pvt->cursor.col);
1100 }
1101 /* Now for the rest of the lines. */
1102 for (i = terminal->pvt->cursor.row + 1;
1103 i < _vte_ring_next(screen->row_data);
1104 i++) {
1105 /* Get the data for the row we're removing. */
1106 rowdata = _vte_ring_index_writable (screen->row_data, i);
1107 /* Remove it. */
1108 if (rowdata)
1109 _vte_row_data_shrink (rowdata, 0);
1110 }
1111 /* Now fill the cleared areas. */
1112 for (i = terminal->pvt->cursor.row;
1113 i < screen->insert_delta + terminal->pvt->row_count;
1114 i++) {
1115 /* Retrieve the row's data, creating it if necessary. */
1116 if (_vte_ring_contains (screen->row_data, i)) {
1117 rowdata = _vte_ring_index_writable (screen->row_data, i);
1118 g_assert(rowdata != NULL);
1119 } else {
1120 rowdata = _vte_terminal_ring_append (terminal, FALSE);
1121 }
1122 /* Pad out the row. */
1123 if (terminal->pvt->fill_defaults.attr.back != VTE_DEFAULT_BG) {
1124 _vte_row_data_fill (rowdata, &terminal->pvt->fill_defaults, terminal->pvt->column_count);
1125 }
1126 rowdata->attr.soft_wrapped = 0;
1127 /* Repaint this row. */
1128 _vte_invalidate_cells(terminal,
1129 0, terminal->pvt->column_count,
1130 i, 1);
1131 }
1132
1133 /* We've modified the display. Make a note of it. */
1134 terminal->pvt->text_deleted_flag = TRUE;
1135 }
1136
1137 /* Clear from the cursor position to the end of the line. */
1138 static void
_vte_sequence_handler_ce(VteTerminal * terminal,GValueArray * params)1139 _vte_sequence_handler_ce (VteTerminal *terminal, GValueArray *params)
1140 {
1141 VteRowData *rowdata;
1142
1143 /* If we were to strictly emulate xterm, we'd ensure the cursor is onscreen.
1144 * But due to https://bugzilla.gnome.org/show_bug.cgi?id=740789 we intentionally
1145 * deviate and do instead what konsole does. This way emitting a \e[K doesn't
1146 * influence the text flow, and serves as a perfect workaround against a new line
1147 * getting painted with the active background color (except for a possible flicker).
1148 */
1149 /* _vte_terminal_ensure_cursor_is_onscreen(terminal); */
1150
1151 /* Get the data for the row which the cursor points to. */
1152 rowdata = _vte_terminal_ensure_row(terminal);
1153 g_assert(rowdata != NULL);
1154 if ((glong) _vte_row_data_length (rowdata) > terminal->pvt->cursor.col) {
1155 /* Clean up Tab/CJK fragments. */
1156 _vte_terminal_cleanup_fragments (terminal, terminal->pvt->cursor.col, _vte_row_data_length (rowdata));
1157 /* Remove the data at the end of the array until the current column
1158 * is the end of the array. */
1159 _vte_row_data_shrink (rowdata, terminal->pvt->cursor.col);
1160 /* We've modified the display. Make a note of it. */
1161 terminal->pvt->text_deleted_flag = TRUE;
1162 }
1163 if (terminal->pvt->fill_defaults.attr.back != VTE_DEFAULT_BG) {
1164 /* Add enough cells to fill out the row. */
1165 _vte_row_data_fill (rowdata, &terminal->pvt->fill_defaults, terminal->pvt->column_count);
1166 }
1167 rowdata->attr.soft_wrapped = 0;
1168 /* Repaint this row. */
1169 _vte_invalidate_cells(terminal,
1170 terminal->pvt->cursor.col,
1171 terminal->pvt->column_count -
1172 terminal->pvt->cursor.col,
1173 terminal->pvt->cursor.row, 1);
1174 }
1175
1176 /* Move the cursor to the given column (horizontal position), 1-based. */
1177 static void
vte_sequence_handler_cursor_character_absolute(VteTerminal * terminal,GValueArray * params)1178 vte_sequence_handler_cursor_character_absolute (VteTerminal *terminal, GValueArray *params)
1179 {
1180 GValue *value;
1181 long val;
1182
1183 val = 0;
1184 if ((params != NULL) && (params->n_values > 0)) {
1185 value = g_value_array_get_nth(params, 0);
1186 if (G_VALUE_HOLDS_LONG(value)) {
1187 val = CLAMP(g_value_get_long(value) - 1,
1188 0,
1189 terminal->pvt->column_count - 1);
1190 }
1191 }
1192
1193 terminal->pvt->cursor.col = val;
1194 }
1195
1196 /* Move the cursor to the given position, 1-based. */
1197 static void
vte_sequence_handler_cursor_position(VteTerminal * terminal,GValueArray * params)1198 vte_sequence_handler_cursor_position (VteTerminal *terminal, GValueArray *params)
1199 {
1200 GValue *row, *col;
1201 long rowval, colval, origin, rowmax;
1202 VteScreen *screen;
1203
1204 screen = terminal->pvt->screen;
1205
1206 /* We need at least two parameters. */
1207 rowval = colval = 0;
1208 if (params != NULL && params->n_values >= 1) {
1209 /* The first is the row, the second is the column. */
1210 row = g_value_array_get_nth(params, 0);
1211 if (G_VALUE_HOLDS_LONG(row)) {
1212 if (terminal->pvt->origin_mode &&
1213 terminal->pvt->scrolling_restricted) {
1214 origin = terminal->pvt->scrolling_region.start;
1215 rowmax = terminal->pvt->scrolling_region.end;
1216 } else {
1217 origin = 0;
1218 rowmax = terminal->pvt->row_count - 1;
1219 }
1220 rowval = g_value_get_long(row) - 1 + origin;
1221 rowval = CLAMP(rowval, origin, rowmax);
1222 }
1223 if (params->n_values >= 2) {
1224 col = g_value_array_get_nth(params, 1);
1225 if (G_VALUE_HOLDS_LONG(col)) {
1226 colval = g_value_get_long(col) - 1;
1227 colval = CLAMP(colval, 0, terminal->pvt->column_count - 1);
1228 }
1229 }
1230 }
1231 terminal->pvt->cursor.row = rowval + screen->insert_delta;
1232 terminal->pvt->cursor.col = colval;
1233 }
1234
1235 /* Carriage return. */
1236 static void
vte_sequence_handler_carriage_return(VteTerminal * terminal,GValueArray * params)1237 vte_sequence_handler_carriage_return (VteTerminal *terminal, GValueArray *params)
1238 {
1239 terminal->pvt->cursor.col = 0;
1240 }
1241
1242 /* Restrict scrolling and updates to a subset of the visible lines. */
1243 static void
vte_sequence_handler_set_scrolling_region(VteTerminal * terminal,GValueArray * params)1244 vte_sequence_handler_set_scrolling_region (VteTerminal *terminal, GValueArray *params)
1245 {
1246 long start=-1, end=-1, rows;
1247 GValue *value;
1248 VteScreen *screen;
1249
1250 /* We require two parameters. Anything less is a reset. */
1251 screen = terminal->pvt->screen;
1252 if ((params == NULL) || (params->n_values < 2)) {
1253 terminal->pvt->scrolling_restricted = FALSE;
1254 _vte_terminal_home_cursor (terminal);
1255 return;
1256 }
1257 /* Extract the two values. */
1258 value = g_value_array_get_nth(params, 0);
1259 if (G_VALUE_HOLDS_LONG(value)) {
1260 start = g_value_get_long(value) - 1;
1261 }
1262 value = g_value_array_get_nth(params, 1);
1263 if (G_VALUE_HOLDS_LONG(value)) {
1264 end = g_value_get_long(value) - 1;
1265 }
1266 rows = terminal->pvt->row_count;
1267 /* A (1-based) value of 0 means default. */
1268 if (start == -1) {
1269 start = 0;
1270 }
1271 if (end == -1) {
1272 end = rows - 1;
1273 }
1274 /* Bail out on garbage, require at least 2 rows, as per xterm. */
1275 if (start < 0 || start >= rows - 1 || end < start + 1) {
1276 return;
1277 }
1278 if (end >= rows) {
1279 end = rows - 1;
1280 }
1281
1282 /* Set the right values. */
1283 terminal->pvt->scrolling_region.start = start;
1284 terminal->pvt->scrolling_region.end = end;
1285 terminal->pvt->scrolling_restricted = TRUE;
1286 if (terminal->pvt->scrolling_region.start == 0 &&
1287 terminal->pvt->scrolling_region.end == rows - 1) {
1288 /* Special case -- run wild, run free. */
1289 terminal->pvt->scrolling_restricted = FALSE;
1290 } else {
1291 /* Maybe extend the ring -- bug 710483 */
1292 while (_vte_ring_next(screen->row_data) < screen->insert_delta + rows)
1293 _vte_ring_insert(screen->row_data, _vte_ring_next(screen->row_data));
1294 }
1295
1296 _vte_terminal_home_cursor (terminal);
1297 }
1298
1299 /* Move the cursor to the beginning of the Nth next line, no scrolling. */
1300 static void
vte_sequence_handler_cursor_next_line(VteTerminal * terminal,GValueArray * params)1301 vte_sequence_handler_cursor_next_line (VteTerminal *terminal, GValueArray *params)
1302 {
1303 terminal->pvt->cursor.col = 0;
1304 vte_sequence_handler_cursor_down (terminal, params);
1305 }
1306
1307 /* Move the cursor to the beginning of the Nth previous line, no scrolling. */
1308 static void
vte_sequence_handler_cursor_preceding_line(VteTerminal * terminal,GValueArray * params)1309 vte_sequence_handler_cursor_preceding_line (VteTerminal *terminal, GValueArray *params)
1310 {
1311 terminal->pvt->cursor.col = 0;
1312 vte_sequence_handler_cursor_up (terminal, params);
1313 }
1314
1315 /* Move the cursor to the given row (vertical position), 1-based. */
1316 static void
vte_sequence_handler_line_position_absolute(VteTerminal * terminal,GValueArray * params)1317 vte_sequence_handler_line_position_absolute (VteTerminal *terminal, GValueArray *params)
1318 {
1319 VteScreen *screen;
1320 GValue *value;
1321 long val = 1, origin, rowmax;
1322 screen = terminal->pvt->screen;
1323
1324 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1325
1326 if ((params != NULL) && (params->n_values > 0)) {
1327 value = g_value_array_get_nth(params, 0);
1328 if (G_VALUE_HOLDS_LONG(value)) {
1329 val = g_value_get_long(value);
1330 }
1331 }
1332
1333 if (terminal->pvt->origin_mode &&
1334 terminal->pvt->scrolling_restricted) {
1335 origin = terminal->pvt->scrolling_region.start;
1336 rowmax = terminal->pvt->scrolling_region.end;
1337 } else {
1338 origin = 0;
1339 rowmax = terminal->pvt->row_count - 1;
1340 }
1341 val = val - 1 + origin;
1342 val = CLAMP(val, origin, rowmax);
1343 terminal->pvt->cursor.row = screen->insert_delta + val;
1344 }
1345
1346 /* Delete a character at the current cursor position. */
1347 static void
_vte_sequence_handler_dc(VteTerminal * terminal,GValueArray * params)1348 _vte_sequence_handler_dc (VteTerminal *terminal, GValueArray *params)
1349 {
1350 VteScreen *screen;
1351 VteRowData *rowdata;
1352 long col;
1353
1354 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1355
1356 screen = terminal->pvt->screen;
1357
1358 if (_vte_ring_next(screen->row_data) > terminal->pvt->cursor.row) {
1359 long len;
1360 /* Get the data for the row which the cursor points to. */
1361 rowdata = _vte_ring_index_writable (screen->row_data, terminal->pvt->cursor.row);
1362 g_assert(rowdata != NULL);
1363 col = terminal->pvt->cursor.col;
1364 len = _vte_row_data_length (rowdata);
1365 /* Remove the column. */
1366 if (col < len) {
1367 /* Clean up Tab/CJK fragments. */
1368 _vte_terminal_cleanup_fragments (terminal, col, col + 1);
1369 _vte_row_data_remove (rowdata, col);
1370 if (terminal->pvt->fill_defaults.attr.back != VTE_DEFAULT_BG) {
1371 _vte_row_data_fill (rowdata, &terminal->pvt->fill_defaults, terminal->pvt->column_count);
1372 len = terminal->pvt->column_count;
1373 }
1374 /* Repaint this row. */
1375 _vte_invalidate_cells(terminal,
1376 col, len - col,
1377 terminal->pvt->cursor.row, 1);
1378 }
1379 }
1380
1381 /* We've modified the display. Make a note of it. */
1382 terminal->pvt->text_deleted_flag = TRUE;
1383 }
1384
1385 /* Delete N characters at the current cursor position. */
1386 static void
vte_sequence_handler_delete_characters(VteTerminal * terminal,GValueArray * params)1387 vte_sequence_handler_delete_characters (VteTerminal *terminal, GValueArray *params)
1388 {
1389 vte_sequence_handler_multiple_r(terminal, params, _vte_sequence_handler_dc);
1390 }
1391
1392 /* Cursor down N lines, no scrolling. */
1393 static void
vte_sequence_handler_cursor_down(VteTerminal * terminal,GValueArray * params)1394 vte_sequence_handler_cursor_down (VteTerminal *terminal, GValueArray *params)
1395 {
1396 long end;
1397 VteScreen *screen;
1398 GValue *value;
1399 long val;
1400
1401 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1402
1403 screen = terminal->pvt->screen;
1404
1405 if (terminal->pvt->scrolling_restricted) {
1406 end = screen->insert_delta + terminal->pvt->scrolling_region.end;
1407 } else {
1408 end = screen->insert_delta + terminal->pvt->row_count - 1;
1409 }
1410
1411 val = 1;
1412 if (params != NULL && params->n_values >= 1) {
1413 value = g_value_array_get_nth(params, 0);
1414 if (G_VALUE_HOLDS_LONG(value)) {
1415 val = CLAMP(g_value_get_long(value),
1416 1, terminal->pvt->row_count);
1417 }
1418 }
1419
1420 terminal->pvt->cursor.row = MIN(terminal->pvt->cursor.row + val, end);
1421 }
1422
1423 /* Erase characters starting at the cursor position (overwriting N with
1424 * spaces, but not moving the cursor). */
1425 static void
vte_sequence_handler_erase_characters(VteTerminal * terminal,GValueArray * params)1426 vte_sequence_handler_erase_characters (VteTerminal *terminal, GValueArray *params)
1427 {
1428 VteScreen *screen;
1429 VteRowData *rowdata;
1430 GValue *value;
1431 VteCell *cell;
1432 long col, i, count;
1433
1434 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1435
1436 screen = terminal->pvt->screen;
1437
1438 /* If we got a parameter, use it. */
1439 count = 1;
1440 if ((params != NULL) && (params->n_values > 0)) {
1441 value = g_value_array_get_nth(params, 0);
1442 if (G_VALUE_HOLDS_LONG(value)) {
1443 count = g_value_get_long(value);
1444 }
1445 }
1446
1447 /* Clear out the given number of characters. */
1448 rowdata = _vte_terminal_ensure_row(terminal);
1449 if (_vte_ring_next(screen->row_data) > terminal->pvt->cursor.row) {
1450 g_assert(rowdata != NULL);
1451 /* Clean up Tab/CJK fragments. */
1452 _vte_terminal_cleanup_fragments (terminal, terminal->pvt->cursor.col, terminal->pvt->cursor.col + count);
1453 /* Write over the characters. (If there aren't enough, we'll
1454 * need to create them.) */
1455 for (i = 0; i < count; i++) {
1456 col = terminal->pvt->cursor.col + i;
1457 if (col >= 0) {
1458 if (col < (glong) _vte_row_data_length (rowdata)) {
1459 /* Replace this cell with the current
1460 * defaults. */
1461 cell = _vte_row_data_get_writable (rowdata, col);
1462 *cell = terminal->pvt->color_defaults;
1463 } else {
1464 /* Add new cells until we have one here. */
1465 _vte_row_data_fill (rowdata, &terminal->pvt->color_defaults, col + 1);
1466 }
1467 }
1468 }
1469 /* Repaint this row. */
1470 _vte_invalidate_cells(terminal,
1471 terminal->pvt->cursor.col, count,
1472 terminal->pvt->cursor.row, 1);
1473 }
1474
1475 /* We've modified the display. Make a note of it. */
1476 terminal->pvt->text_deleted_flag = TRUE;
1477 }
1478
1479 /* Form-feed / next-page. */
1480 static void
vte_sequence_handler_form_feed(VteTerminal * terminal,GValueArray * params)1481 vte_sequence_handler_form_feed (VteTerminal *terminal, GValueArray *params)
1482 {
1483 vte_sequence_handler_line_feed (terminal, params);
1484 }
1485
1486 /* Insert a blank character. */
1487 static void
_vte_sequence_handler_insert_character(VteTerminal * terminal,GValueArray * params)1488 _vte_sequence_handler_insert_character (VteTerminal *terminal, GValueArray *params)
1489 {
1490 VteVisualPosition save;
1491
1492 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1493
1494 save = terminal->pvt->cursor;
1495
1496 _vte_terminal_insert_char(terminal, ' ', TRUE, TRUE);
1497
1498 terminal->pvt->cursor = save;
1499 }
1500
1501 /* Insert N blank characters. */
1502 /* TODOegmont: Insert them in a single run, so that we call _vte_terminal_cleanup_fragments only once. */
1503 static void
vte_sequence_handler_insert_blank_characters(VteTerminal * terminal,GValueArray * params)1504 vte_sequence_handler_insert_blank_characters (VteTerminal *terminal, GValueArray *params)
1505 {
1506 vte_sequence_handler_multiple_r(terminal, params, _vte_sequence_handler_insert_character);
1507 }
1508
1509 /* Cursor down 1 line, with scrolling. */
1510 static void
vte_sequence_handler_index(VteTerminal * terminal,GValueArray * params)1511 vte_sequence_handler_index (VteTerminal *terminal, GValueArray *params)
1512 {
1513 vte_sequence_handler_line_feed (terminal, params);
1514 }
1515
1516 /* Cursor left. */
1517 static void
vte_sequence_handler_backspace(VteTerminal * terminal,GValueArray * params)1518 vte_sequence_handler_backspace (VteTerminal *terminal, GValueArray *params)
1519 {
1520 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1521
1522 if (terminal->pvt->cursor.col > 0) {
1523 /* There's room to move left, so do so. */
1524 terminal->pvt->cursor.col--;
1525 }
1526 }
1527
1528 /* Cursor left N columns. */
1529 static void
vte_sequence_handler_cursor_backward(VteTerminal * terminal,GValueArray * params)1530 vte_sequence_handler_cursor_backward (VteTerminal *terminal, GValueArray *params)
1531 {
1532 GValue *value;
1533 long val;
1534
1535 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1536
1537 val = 1;
1538 if (params != NULL && params->n_values >= 1) {
1539 value = g_value_array_get_nth(params, 0);
1540 if (G_VALUE_HOLDS_LONG(value)) {
1541 val = MAX(g_value_get_long(value), 1);
1542 }
1543 }
1544 terminal->pvt->cursor.col = MAX(terminal->pvt->cursor.col - val, 0);
1545 }
1546
1547 /* Cursor right N columns. */
1548 static void
vte_sequence_handler_cursor_forward(VteTerminal * terminal,GValueArray * params)1549 vte_sequence_handler_cursor_forward (VteTerminal *terminal, GValueArray *params)
1550 {
1551 GValue *value;
1552 long val;
1553
1554 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1555
1556 val = 1;
1557 if (params != NULL && params->n_values >= 1) {
1558 value = g_value_array_get_nth(params, 0);
1559 if (G_VALUE_HOLDS_LONG(value)) {
1560 val = CLAMP(g_value_get_long(value),
1561 1, terminal->pvt->column_count);
1562 }
1563 }
1564 /* The cursor can be further to the right, don't move in that case. */
1565 if (terminal->pvt->cursor.col < terminal->pvt->column_count) {
1566 /* There's room to move right. */
1567 terminal->pvt->cursor.col = MIN(terminal->pvt->cursor.col + val,
1568 terminal->pvt->column_count - 1);
1569 }
1570 }
1571
1572 /* Move the cursor to the beginning of the next line, scrolling if necessary. */
1573 static void
vte_sequence_handler_next_line(VteTerminal * terminal,GValueArray * params)1574 vte_sequence_handler_next_line (VteTerminal *terminal, GValueArray *params)
1575 {
1576 terminal->pvt->cursor.col = 0;
1577 _vte_terminal_cursor_down (terminal);
1578 }
1579
1580 /* No-op. */
1581 static void
vte_sequence_handler_linux_console_cursor_attributes(VteTerminal * terminal,GValueArray * params)1582 vte_sequence_handler_linux_console_cursor_attributes (VteTerminal *terminal, GValueArray *params)
1583 {
1584 }
1585
1586 /* Scroll the text down N lines, but don't move the cursor. */
1587 static void
vte_sequence_handler_scroll_down(VteTerminal * terminal,GValueArray * params)1588 vte_sequence_handler_scroll_down (VteTerminal *terminal, GValueArray *params)
1589 {
1590 long val = 1;
1591 GValue *value;
1592
1593 /* No _vte_terminal_ensure_cursor_is_onscreen() here as per xterm */
1594
1595 if ((params != NULL) && (params->n_values > 0)) {
1596 value = g_value_array_get_nth(params, 0);
1597 if (G_VALUE_HOLDS_LONG(value)) {
1598 val = g_value_get_long(value);
1599 val = MAX(val, 1);
1600 }
1601 }
1602
1603 _vte_terminal_scroll_text (terminal, val);
1604 }
1605
1606 /* Internal helper for changing color in the palette */
1607 static void
vte_sequence_handler_change_color_internal(VteTerminal * terminal,GValueArray * params,const char * terminator)1608 vte_sequence_handler_change_color_internal (VteTerminal *terminal, GValueArray *params,
1609 const char *terminator)
1610 {
1611 gchar **pairs, *str = NULL;
1612 GValue *value;
1613 PangoColor color;
1614 guint idx, i;
1615
1616 if (params != NULL && params->n_values > 0) {
1617 value = g_value_array_get_nth (params, 0);
1618
1619 if (G_VALUE_HOLDS_STRING (value))
1620 str = g_value_dup_string (value);
1621 else if (G_VALUE_HOLDS_POINTER (value))
1622 str = vte_ucs4_to_utf8 (terminal, g_value_get_pointer (value));
1623
1624 if (! str)
1625 return;
1626
1627 pairs = g_strsplit (str, ";", 0);
1628 if (! pairs) {
1629 g_free (str);
1630 return;
1631 }
1632
1633 for (i = 0; pairs[i] && pairs[i + 1]; i += 2) {
1634 idx = strtoul (pairs[i], (char **) NULL, 10);
1635
1636 if (idx >= VTE_DEFAULT_FG)
1637 continue;
1638
1639 if (vte_parse_color (pairs[i + 1], &color)) {
1640 _vte_terminal_set_color_internal(terminal, idx, VTE_COLOR_SOURCE_ESCAPE, &color);
1641 } else if (strcmp (pairs[i + 1], "?") == 0) {
1642 gchar buf[128];
1643 PangoColor *c = _vte_terminal_get_color(terminal, idx);
1644 g_assert(c != NULL);
1645 g_snprintf (buf, sizeof (buf),
1646 _VTE_CAP_OSC "4;%u;rgb:%04x/%04x/%04x%s",
1647 idx, c->red, c->green, c->blue, terminator);
1648 vte_terminal_feed_child (terminal, buf, -1);
1649 }
1650 }
1651
1652 g_free (str);
1653 g_strfreev (pairs);
1654
1655 /* emit the refresh as the palette has changed and previous
1656 * renders need to be updated. */
1657 vte_terminal_emit_refresh_window (terminal);
1658 }
1659 }
1660
1661 /* Change color in the palette, BEL terminated */
1662 static void
vte_sequence_handler_change_color_bel(VteTerminal * terminal,GValueArray * params)1663 vte_sequence_handler_change_color_bel (VteTerminal *terminal, GValueArray *params)
1664 {
1665 vte_sequence_handler_change_color_internal (terminal, params, BEL);
1666 }
1667
1668 /* Change color in the palette, ST terminated */
1669 static void
vte_sequence_handler_change_color_st(VteTerminal * terminal,GValueArray * params)1670 vte_sequence_handler_change_color_st (VteTerminal *terminal, GValueArray *params)
1671 {
1672 vte_sequence_handler_change_color_internal (terminal, params, ST);
1673 }
1674
1675 /* Reset color in the palette */
1676 static void
vte_sequence_handler_reset_color(VteTerminal * terminal,GValueArray * params)1677 vte_sequence_handler_reset_color (VteTerminal *terminal, GValueArray *params)
1678 {
1679 GValue *value;
1680 guint i;
1681 long idx;
1682
1683 if (params != NULL && params->n_values > 0) {
1684 for (i = 0; i < params->n_values; i++) {
1685 value = g_value_array_get_nth (params, i);
1686
1687 if (!G_VALUE_HOLDS_LONG (value))
1688 continue;
1689 idx = g_value_get_long (value);
1690 if (idx < 0 || idx >= VTE_DEFAULT_FG)
1691 continue;
1692
1693 _vte_terminal_set_color_internal(terminal, idx, VTE_COLOR_SOURCE_ESCAPE, NULL);
1694 }
1695 } else {
1696 for (idx = 0; idx < VTE_DEFAULT_FG; idx++) {
1697 _vte_terminal_set_color_internal(terminal, idx, VTE_COLOR_SOURCE_ESCAPE, NULL);
1698 }
1699 }
1700 }
1701
1702 /* Scroll the text up N lines, but don't move the cursor. */
1703 static void
vte_sequence_handler_scroll_up(VteTerminal * terminal,GValueArray * params)1704 vte_sequence_handler_scroll_up (VteTerminal *terminal, GValueArray *params)
1705 {
1706 long val = 1;
1707 GValue *value;
1708
1709 /* No _vte_terminal_ensure_cursor_is_onscreen() here as per xterm */
1710
1711 if ((params != NULL) && (params->n_values > 0)) {
1712 value = g_value_array_get_nth(params, 0);
1713 if (G_VALUE_HOLDS_LONG(value)) {
1714 val = g_value_get_long(value);
1715 val = MAX(val, 1);
1716 }
1717 }
1718
1719 _vte_terminal_scroll_text (terminal, -val);
1720 }
1721
1722 /* Cursor down 1 line, with scrolling. */
1723 static void
vte_sequence_handler_line_feed(VteTerminal * terminal,GValueArray * params)1724 vte_sequence_handler_line_feed (VteTerminal *terminal, GValueArray *params)
1725 {
1726 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1727
1728 _vte_terminal_cursor_down (terminal);
1729 }
1730
1731 /* Cursor up 1 line, with scrolling. */
1732 static void
vte_sequence_handler_reverse_index(VteTerminal * terminal,GValueArray * params)1733 vte_sequence_handler_reverse_index (VteTerminal *terminal, GValueArray *params)
1734 {
1735 long start, end;
1736 VteScreen *screen;
1737
1738 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1739
1740 screen = terminal->pvt->screen;
1741
1742 if (terminal->pvt->scrolling_restricted) {
1743 start = terminal->pvt->scrolling_region.start + screen->insert_delta;
1744 end = terminal->pvt->scrolling_region.end + screen->insert_delta;
1745 } else {
1746 start = terminal->pvt->screen->insert_delta;
1747 end = start + terminal->pvt->row_count - 1;
1748 }
1749
1750 if (terminal->pvt->cursor.row == start) {
1751 /* If we're at the top of the scrolling region, add a
1752 * line at the top to scroll the bottom off. */
1753 _vte_terminal_ring_remove (terminal, end);
1754 _vte_terminal_ring_insert (terminal, start, TRUE);
1755 /* Update the display. */
1756 _vte_terminal_scroll_region(terminal, start, end - start + 1, 1);
1757 _vte_invalidate_cells(terminal,
1758 0, terminal->pvt->column_count,
1759 start, 2);
1760 } else {
1761 /* Otherwise, just move the cursor up. */
1762 terminal->pvt->cursor.row--;
1763 }
1764 /* Adjust the scrollbars if necessary. */
1765 _vte_terminal_adjust_adjustments(terminal);
1766 /* We modified the display, so make a note of it. */
1767 terminal->pvt->text_modified_flag = TRUE;
1768 }
1769
1770 /* Set tab stop in the current column. */
1771 static void
vte_sequence_handler_tab_set(VteTerminal * terminal,GValueArray * params)1772 vte_sequence_handler_tab_set (VteTerminal *terminal, GValueArray *params)
1773 {
1774 if (terminal->pvt->tabstops == NULL) {
1775 terminal->pvt->tabstops = g_hash_table_new(NULL, NULL);
1776 }
1777 _vte_terminal_set_tabstop(terminal,
1778 terminal->pvt->cursor.col);
1779 }
1780
1781 /* Tab. */
1782 static void
vte_sequence_handler_tab(VteTerminal * terminal,GValueArray * params)1783 vte_sequence_handler_tab (VteTerminal *terminal, GValueArray *params)
1784 {
1785 long old_len, newcol, col;
1786
1787 /* Calculate which column is the next tab stop. */
1788 newcol = col = terminal->pvt->cursor.col;
1789
1790 g_assert (col >= 0);
1791
1792 if (terminal->pvt->tabstops != NULL) {
1793 /* Find the next tabstop. */
1794 for (newcol++; newcol < VTE_TAB_MAX; newcol++) {
1795 if (_vte_terminal_get_tabstop(terminal, newcol)) {
1796 break;
1797 }
1798 }
1799 }
1800
1801 /* If we have no tab stops or went past the end of the line, stop
1802 * at the right-most column. */
1803 if (newcol >= terminal->pvt->column_count) {
1804 newcol = terminal->pvt->column_count - 1;
1805 }
1806
1807 /* but make sure we don't move cursor back (bug #340631) */
1808 if (col < newcol) {
1809 VteRowData *rowdata = _vte_terminal_ensure_row (terminal);
1810
1811 /* Smart tab handling: bug 353610
1812 *
1813 * If we currently don't have any cells in the space this
1814 * tab creates, we try to make the tab character copyable,
1815 * by appending a single tab char with lots of fragment
1816 * cells following it.
1817 *
1818 * Otherwise, just append empty cells that will show up
1819 * as a space each.
1820 */
1821
1822 old_len = _vte_row_data_length (rowdata);
1823 _vte_row_data_fill (rowdata, &terminal->pvt->fill_defaults, newcol);
1824
1825 /* Insert smart tab if there's nothing in the line after
1826 * us. Though, there may be empty cells (with non-default
1827 * background color for example.
1828 *
1829 * Notable bugs here: 545924 and 597242 */
1830 {
1831 glong i;
1832 gboolean found = FALSE;
1833 for (i = old_len; i > col; i--) {
1834 const VteCell *cell = _vte_row_data_get (rowdata, i - 1);
1835 if (cell->attr.fragment || cell->c != 0) {
1836 found = TRUE;
1837 break;
1838 }
1839 }
1840 /* Nothing found on the line after us, turn this into
1841 * a smart tab */
1842 if (!found && newcol - col <= VTE_TAB_WIDTH_MAX) {
1843 VteCell *cell = _vte_row_data_get_writable (rowdata, col);
1844 VteCell tab = *cell;
1845 tab.attr.columns = newcol - col;
1846 tab.c = '\t';
1847 /* Save tab char */
1848 *cell = tab;
1849 /* And adjust the fragments */
1850 for (i = col + 1; i < newcol; i++) {
1851 cell = _vte_row_data_get_writable (rowdata, i);
1852 cell->c = '\t';
1853 cell->attr.columns = 1;
1854 cell->attr.fragment = 1;
1855 }
1856 }
1857 }
1858
1859 _vte_invalidate_cells (terminal,
1860 terminal->pvt->cursor.col,
1861 newcol - terminal->pvt->cursor.col,
1862 terminal->pvt->cursor.row, 1);
1863 terminal->pvt->cursor.col = newcol;
1864 }
1865 }
1866
1867 static void
vte_sequence_handler_cursor_forward_tabulation(VteTerminal * terminal,GValueArray * params)1868 vte_sequence_handler_cursor_forward_tabulation (VteTerminal *terminal, GValueArray *params)
1869 {
1870 vte_sequence_handler_multiple_r(terminal, params, vte_sequence_handler_tab);
1871 }
1872
1873 /* Clear tabs selectively. */
1874 static void
vte_sequence_handler_tab_clear(VteTerminal * terminal,GValueArray * params)1875 vte_sequence_handler_tab_clear (VteTerminal *terminal, GValueArray *params)
1876 {
1877 GValue *value;
1878 long param = 0;
1879
1880 if ((params != NULL) && (params->n_values > 0)) {
1881 value = g_value_array_get_nth(params, 0);
1882 if (G_VALUE_HOLDS_LONG(value)) {
1883 param = g_value_get_long(value);
1884 }
1885 }
1886 if (param == 0) {
1887 _vte_terminal_clear_tabstop(terminal,
1888 terminal->pvt->cursor.col);
1889 } else
1890 if (param == 3) {
1891 if (terminal->pvt->tabstops != NULL) {
1892 g_hash_table_destroy(terminal->pvt->tabstops);
1893 terminal->pvt->tabstops = NULL;
1894 }
1895 }
1896 }
1897
1898 /* Cursor up N lines, no scrolling. */
1899 static void
vte_sequence_handler_cursor_up(VteTerminal * terminal,GValueArray * params)1900 vte_sequence_handler_cursor_up (VteTerminal *terminal, GValueArray *params)
1901 {
1902 VteScreen *screen;
1903 long start;
1904 GValue *value;
1905 long val;
1906
1907 _vte_terminal_ensure_cursor_is_onscreen(terminal);
1908
1909 screen = terminal->pvt->screen;
1910
1911 if (terminal->pvt->scrolling_restricted) {
1912 start = screen->insert_delta + terminal->pvt->scrolling_region.start;
1913 } else {
1914 start = screen->insert_delta;
1915 }
1916
1917 val = 1;
1918 if (params != NULL && params->n_values >= 1) {
1919 value = g_value_array_get_nth(params, 0);
1920 if (G_VALUE_HOLDS_LONG(value)) {
1921 val = CLAMP(g_value_get_long(value),
1922 1, terminal->pvt->row_count);
1923 }
1924 }
1925
1926 terminal->pvt->cursor.row = MAX(terminal->pvt->cursor.row - val, start);
1927 }
1928
1929 /* Vertical tab. */
1930 static void
vte_sequence_handler_vertical_tab(VteTerminal * terminal,GValueArray * params)1931 vte_sequence_handler_vertical_tab (VteTerminal *terminal, GValueArray *params)
1932 {
1933 vte_sequence_handler_line_feed (terminal, params);
1934 }
1935
1936 /* Parse parameters of SGR 38 or 48, starting at @index within @params.
1937 * Returns the color index, or -1 on error.
1938 * Increments @index to point to the last consumed parameter (not beyond). */
1939 static gint32
vte_sequence_parse_sgr_38_48_parameters(GValueArray * params,unsigned int * index)1940 vte_sequence_parse_sgr_38_48_parameters (GValueArray *params, unsigned int *index)
1941 {
1942 if (*index < params->n_values) {
1943 GValue *value0, *value1, *value2, *value3;
1944 long param0, param1, param2, param3;
1945 value0 = g_value_array_get_nth(params, *index);
1946 if (G_UNLIKELY (!G_VALUE_HOLDS_LONG(value0)))
1947 return -1;
1948 param0 = g_value_get_long(value0);
1949 switch (param0) {
1950 case 2:
1951 if (G_UNLIKELY (*index + 3 >= params->n_values))
1952 return -1;
1953 value1 = g_value_array_get_nth(params, *index + 1);
1954 value2 = g_value_array_get_nth(params, *index + 2);
1955 value3 = g_value_array_get_nth(params, *index + 3);
1956 if (G_UNLIKELY (!(G_VALUE_HOLDS_LONG(value1) && G_VALUE_HOLDS_LONG(value2) && G_VALUE_HOLDS_LONG(value3))))
1957 return -1;
1958 param1 = g_value_get_long(value1);
1959 param2 = g_value_get_long(value2);
1960 param3 = g_value_get_long(value3);
1961 if (G_UNLIKELY (param1 < 0 || param1 >= 256 || param2 < 0 || param2 >= 256 || param3 < 0 || param3 >= 256))
1962 return -1;
1963 *index += 3;
1964 return VTE_RGB_COLOR | (param1 << 16) | (param2 << 8) | param3;
1965 case 5:
1966 if (G_UNLIKELY (*index + 1 >= params->n_values))
1967 return -1;
1968 value1 = g_value_array_get_nth(params, *index + 1);
1969 if (G_UNLIKELY (!G_VALUE_HOLDS_LONG(value1)))
1970 return -1;
1971 param1 = g_value_get_long(value1);
1972 if (G_UNLIKELY (param1 < 0 || param1 >= 256))
1973 return -1;
1974 *index += 1;
1975 return param1;
1976 }
1977 }
1978 return -1;
1979 }
1980
1981 /* Handle ANSI color setting and related stuffs (SGR).
1982 * @params contains the values split at semicolons, with sub arrays splitting at colons
1983 * wherever colons were encountered. */
1984 static void
vte_sequence_handler_character_attributes(VteTerminal * terminal,GValueArray * params)1985 vte_sequence_handler_character_attributes (VteTerminal *terminal, GValueArray *params)
1986 {
1987 unsigned int i;
1988 GValue *value;
1989 long param;
1990 /* The default parameter is zero. */
1991 param = 0;
1992 /* Step through each numeric parameter. */
1993 for (i = 0; (params != NULL) && (i < params->n_values); i++) {
1994 value = g_value_array_get_nth(params, i);
1995 /* If this parameter is a GValueArray, it can be a fully colon separated 38 or 48
1996 * (see below for details). */
1997 if (G_UNLIKELY (G_VALUE_HOLDS_BOXED(value))) {
1998 GValueArray *subvalues = g_value_get_boxed(value);
1999 GValue *value0;
2000 long param0;
2001 gint32 color;
2002 unsigned int index = 1;
2003
2004 value0 = g_value_array_get_nth(subvalues, 0);
2005 if (G_UNLIKELY (!G_VALUE_HOLDS_LONG(value0)))
2006 continue;
2007 param0 = g_value_get_long(value0);
2008 if (G_UNLIKELY (param0 != 38 && param0 != 48))
2009 continue;
2010 color = vte_sequence_parse_sgr_38_48_parameters(subvalues, &index);
2011 /* Bail out on additional colon-separated values. */
2012 if (G_UNLIKELY (index != subvalues->n_values - 1))
2013 continue;
2014 if (G_LIKELY (color != -1)) {
2015 if (param0 == 38) {
2016 terminal->pvt->defaults.attr.fore = color;
2017 } else {
2018 terminal->pvt->defaults.attr.back = color;
2019 }
2020 }
2021 continue;
2022 }
2023 /* If this parameter is not a GValueArray and not a number either, skip it. */
2024 if (!G_VALUE_HOLDS_LONG(value)) {
2025 continue;
2026 }
2027 param = g_value_get_long(value);
2028 switch (param) {
2029 case 0:
2030 _vte_terminal_set_default_attributes(terminal);
2031 break;
2032 case 1:
2033 terminal->pvt->defaults.attr.bold = 1;
2034 break;
2035 case 2:
2036 terminal->pvt->defaults.attr.dim = 1;
2037 break;
2038 case 3:
2039 terminal->pvt->defaults.attr.italic = 1;
2040 break;
2041 case 4:
2042 terminal->pvt->defaults.attr.underline = 1;
2043 break;
2044 case 5:
2045 terminal->pvt->defaults.attr.blink = 1;
2046 break;
2047 case 7:
2048 terminal->pvt->defaults.attr.reverse = 1;
2049 break;
2050 case 8:
2051 terminal->pvt->defaults.attr.invisible = 1;
2052 break;
2053 case 9:
2054 terminal->pvt->defaults.attr.strikethrough = 1;
2055 break;
2056 case 21: /* Error in old versions of linux console. */
2057 case 22: /* ECMA 48. */
2058 terminal->pvt->defaults.attr.bold = 0;
2059 terminal->pvt->defaults.attr.dim = 0;
2060 break;
2061 case 23:
2062 terminal->pvt->defaults.attr.italic = 0;
2063 break;
2064 case 24:
2065 terminal->pvt->defaults.attr.underline = 0;
2066 break;
2067 case 25:
2068 terminal->pvt->defaults.attr.blink = 0;
2069 break;
2070 case 27:
2071 terminal->pvt->defaults.attr.reverse = 0;
2072 break;
2073 case 28:
2074 terminal->pvt->defaults.attr.invisible = 0;
2075 break;
2076 case 29:
2077 terminal->pvt->defaults.attr.strikethrough = 0;
2078 break;
2079 case 30:
2080 case 31:
2081 case 32:
2082 case 33:
2083 case 34:
2084 case 35:
2085 case 36:
2086 case 37:
2087 terminal->pvt->defaults.attr.fore = VTE_LEGACY_COLORS_OFFSET + param - 30;
2088 break;
2089 case 38:
2090 case 48:
2091 {
2092 /* The format looks like:
2093 * - 256 color indexed palette:
2094 * - ^[[38;5;INDEXm
2095 * - ^[[38;5:INDEXm
2096 * - ^[[38:5:INDEXm
2097 * - true colors:
2098 * - ^[[38;2;RED;GREEN;BLUEm
2099 * - ^[[38;2:RED:GREEN:BLUEm
2100 * - ^[[38:2:RED:GREEN:BLUEm
2101 * See bug 685759 for details.
2102 * The fully colon versions were handled above separately. The code is reached
2103 * if the first separator is a semicolon. */
2104 if ((i + 1) < params->n_values) {
2105 gint32 color;
2106 GValue *value1 = g_value_array_get_nth(params, ++i);
2107 if (G_VALUE_HOLDS_LONG(value1)) {
2108 /* Only semicolons as separators. */
2109 color = vte_sequence_parse_sgr_38_48_parameters(params, &i);
2110 } else if (G_VALUE_HOLDS_BOXED(value1)) {
2111 /* The first separator was a semicolon, the rest are colons. */
2112 GValueArray *subvalues = g_value_get_boxed(value1);
2113 unsigned int index = 0;
2114 color = vte_sequence_parse_sgr_38_48_parameters(subvalues, &index);
2115 /* Bail out on additional colon-separated values. */
2116 if (G_UNLIKELY (index != subvalues->n_values - 1))
2117 break;
2118 } else {
2119 break;
2120 }
2121 if (G_LIKELY (color != -1)) {
2122 if (param == 38) {
2123 terminal->pvt->defaults.attr.fore = color;
2124 } else {
2125 terminal->pvt->defaults.attr.back = color;
2126 }
2127 }
2128 }
2129 break;
2130 }
2131 case 39:
2132 /* default foreground */
2133 terminal->pvt->defaults.attr.fore = VTE_DEFAULT_FG;
2134 break;
2135 case 40:
2136 case 41:
2137 case 42:
2138 case 43:
2139 case 44:
2140 case 45:
2141 case 46:
2142 case 47:
2143 terminal->pvt->defaults.attr.back = VTE_LEGACY_COLORS_OFFSET + param - 40;
2144 break;
2145 /* case 48: was handled above at 38 to avoid code duplication */
2146 case 49:
2147 /* default background */
2148 terminal->pvt->defaults.attr.back = VTE_DEFAULT_BG;
2149 break;
2150 case 90:
2151 case 91:
2152 case 92:
2153 case 93:
2154 case 94:
2155 case 95:
2156 case 96:
2157 case 97:
2158 terminal->pvt->defaults.attr.fore = VTE_LEGACY_COLORS_OFFSET + param - 90 + VTE_COLOR_BRIGHT_OFFSET;
2159 break;
2160 case 100:
2161 case 101:
2162 case 102:
2163 case 103:
2164 case 104:
2165 case 105:
2166 case 106:
2167 case 107:
2168 terminal->pvt->defaults.attr.back = VTE_LEGACY_COLORS_OFFSET + param - 100 + VTE_COLOR_BRIGHT_OFFSET;
2169 break;
2170 }
2171 }
2172 /* If we had no parameters, default to the defaults. */
2173 if (i == 0) {
2174 _vte_terminal_set_default_attributes(terminal);
2175 }
2176 /* Save the new colors. */
2177 terminal->pvt->color_defaults.attr.fore =
2178 terminal->pvt->defaults.attr.fore;
2179 terminal->pvt->color_defaults.attr.back =
2180 terminal->pvt->defaults.attr.back;
2181 terminal->pvt->fill_defaults.attr.fore =
2182 terminal->pvt->defaults.attr.fore;
2183 terminal->pvt->fill_defaults.attr.back =
2184 terminal->pvt->defaults.attr.back;
2185 }
2186
2187 /* Move the cursor to the given column in the top row, 1-based. */
2188 static void
vte_sequence_handler_cursor_position_top_row(VteTerminal * terminal,GValueArray * params)2189 vte_sequence_handler_cursor_position_top_row (VteTerminal *terminal, GValueArray *params)
2190 {
2191 GValue value = {0};
2192
2193 g_value_init (&value, G_TYPE_LONG);
2194 g_value_set_long (&value, 1);
2195
2196 g_value_array_insert (params, 0, &value);
2197
2198 vte_sequence_handler_cursor_position(terminal, params);
2199 }
2200
2201 /* Request terminal attributes. */
2202 static void
vte_sequence_handler_request_terminal_parameters(VteTerminal * terminal,GValueArray * params)2203 vte_sequence_handler_request_terminal_parameters (VteTerminal *terminal, GValueArray *params)
2204 {
2205 vte_terminal_feed_child(terminal, "\e[?x", -1);
2206 }
2207
2208 /* Request terminal attributes. */
2209 static void
vte_sequence_handler_return_terminal_status(VteTerminal * terminal,GValueArray * params)2210 vte_sequence_handler_return_terminal_status (VteTerminal *terminal, GValueArray *params)
2211 {
2212 vte_terminal_feed_child(terminal, "", 0);
2213 }
2214
2215 /* Send primary device attributes. */
2216 static void
vte_sequence_handler_send_primary_device_attributes(VteTerminal * terminal,GValueArray * params)2217 vte_sequence_handler_send_primary_device_attributes (VteTerminal *terminal, GValueArray *params)
2218 {
2219 /* Claim to be a VT220 with only national character set support. */
2220 vte_terminal_feed_child(terminal, "\e[?62;c", -1);
2221 }
2222
2223 /* Send terminal ID. */
2224 static void
vte_sequence_handler_return_terminal_id(VteTerminal * terminal,GValueArray * params)2225 vte_sequence_handler_return_terminal_id (VteTerminal *terminal, GValueArray *params)
2226 {
2227 vte_sequence_handler_send_primary_device_attributes (terminal, params);
2228 }
2229
2230 /* Send secondary device attributes. */
2231 static void
vte_sequence_handler_send_secondary_device_attributes(VteTerminal * terminal,GValueArray * params)2232 vte_sequence_handler_send_secondary_device_attributes (VteTerminal *terminal, GValueArray *params)
2233 {
2234 char **version;
2235 char buf[128];
2236 long ver = 0, i;
2237 /* Claim to be a VT220, more or less. The '>' in the response appears
2238 * to be undocumented. */
2239 version = g_strsplit(VERSION, ".", 0);
2240 if (version != NULL) {
2241 for (i = 0; version[i] != NULL; i++) {
2242 ver = ver * 100;
2243 ver += atol(version[i]);
2244 }
2245 g_strfreev(version);
2246 }
2247 g_snprintf(buf, sizeof (buf), _VTE_CAP_ESC "[>1;%ld;0c", ver);
2248 vte_terminal_feed_child(terminal, buf, -1);
2249 }
2250
2251 /* Set one or the other. */
2252 static void
vte_sequence_handler_set_icon_title(VteTerminal * terminal,GValueArray * params)2253 vte_sequence_handler_set_icon_title (VteTerminal *terminal, GValueArray *params)
2254 {
2255 vte_sequence_handler_set_title_internal(terminal, params, TRUE, FALSE);
2256 }
2257
2258 static void
vte_sequence_handler_set_window_title(VteTerminal * terminal,GValueArray * params)2259 vte_sequence_handler_set_window_title (VteTerminal *terminal, GValueArray *params)
2260 {
2261 vte_sequence_handler_set_title_internal(terminal, params, FALSE, TRUE);
2262 }
2263
2264 /* Set both the window and icon titles to the same string. */
2265 static void
vte_sequence_handler_set_icon_and_window_title(VteTerminal * terminal,GValueArray * params)2266 vte_sequence_handler_set_icon_and_window_title (VteTerminal *terminal, GValueArray *params)
2267 {
2268 vte_sequence_handler_set_title_internal(terminal, params, TRUE, TRUE);
2269 }
2270
2271 static void
vte_sequence_handler_set_current_directory_uri(VteTerminal * terminal,GValueArray * params)2272 vte_sequence_handler_set_current_directory_uri (VteTerminal *terminal, GValueArray *params)
2273 {
2274 GValue *value;
2275 char *uri, *filename;
2276
2277 uri = NULL;
2278 if (params != NULL && params->n_values > 0) {
2279 value = g_value_array_get_nth(params, 0);
2280
2281 if (G_VALUE_HOLDS_POINTER(value)) {
2282 uri = vte_ucs4_to_utf8 (terminal, g_value_get_pointer (value));
2283 } else if (G_VALUE_HOLDS_STRING(value)) {
2284 /* Copy the string into the buffer. */
2285 uri = g_value_dup_string(value);
2286 }
2287 }
2288
2289 /* Validate URI */
2290 if (uri && uri[0]) {
2291 filename = g_filename_from_uri (uri, NULL, NULL);
2292 if (filename == NULL) {
2293 /* invalid URI */
2294 g_free (uri);
2295 uri = NULL;
2296 } else {
2297 g_free (filename);
2298 }
2299 }
2300
2301 g_free(terminal->pvt->current_directory_uri_changed);
2302 terminal->pvt->current_directory_uri_changed = uri;
2303 }
2304
2305 static void
vte_sequence_handler_set_current_file_uri(VteTerminal * terminal,GValueArray * params)2306 vte_sequence_handler_set_current_file_uri (VteTerminal *terminal, GValueArray *params)
2307 {
2308 GValue *value;
2309 char *uri, *filename;
2310
2311 uri = NULL;
2312 if (params != NULL && params->n_values > 0) {
2313 value = g_value_array_get_nth(params, 0);
2314
2315 if (G_VALUE_HOLDS_POINTER(value)) {
2316 uri = vte_ucs4_to_utf8 (terminal, g_value_get_pointer (value));
2317 } else if (G_VALUE_HOLDS_STRING(value)) {
2318 /* Copy the string into the buffer. */
2319 uri = g_value_dup_string(value);
2320 }
2321 }
2322
2323 /* Validate URI */
2324 if (uri && uri[0]) {
2325 filename = g_filename_from_uri (uri, NULL, NULL);
2326 if (filename == NULL) {
2327 /* invalid URI */
2328 g_free (uri);
2329 uri = NULL;
2330 } else {
2331 g_free (filename);
2332 }
2333 }
2334
2335 g_free(terminal->pvt->current_file_uri_changed);
2336 terminal->pvt->current_file_uri_changed = uri;
2337 }
2338
2339 /* Restrict the scrolling region. */
2340 static void
vte_sequence_handler_set_scrolling_region_from_start(VteTerminal * terminal,GValueArray * params)2341 vte_sequence_handler_set_scrolling_region_from_start (VteTerminal *terminal, GValueArray *params)
2342 {
2343 GValue value = {0};
2344
2345 g_value_init (&value, G_TYPE_LONG);
2346 g_value_set_long (&value, 0); /* A missing value is treated as 0 */
2347
2348 g_value_array_insert (params, 0, &value);
2349
2350 vte_sequence_handler_set_scrolling_region (terminal, params);
2351 }
2352
2353 static void
vte_sequence_handler_set_scrolling_region_to_end(VteTerminal * terminal,GValueArray * params)2354 vte_sequence_handler_set_scrolling_region_to_end (VteTerminal *terminal, GValueArray *params)
2355 {
2356 GValue value = {0};
2357
2358 g_value_init (&value, G_TYPE_LONG);
2359 g_value_set_long (&value, 0); /* A missing value is treated as 0 */
2360
2361 g_value_array_insert (params, 1, &value);
2362
2363 vte_sequence_handler_set_scrolling_region (terminal, params);
2364 }
2365
2366 /* Set the application or normal keypad. */
2367 static void
vte_sequence_handler_application_keypad(VteTerminal * terminal,GValueArray * params)2368 vte_sequence_handler_application_keypad (VteTerminal *terminal, GValueArray *params)
2369 {
2370 _vte_debug_print(VTE_DEBUG_KEYBOARD,
2371 "Entering application keypad mode.\n");
2372 terminal->pvt->keypad_mode = VTE_KEYMODE_APPLICATION;
2373 }
2374
2375 static void
vte_sequence_handler_normal_keypad(VteTerminal * terminal,GValueArray * params)2376 vte_sequence_handler_normal_keypad (VteTerminal *terminal, GValueArray *params)
2377 {
2378 _vte_debug_print(VTE_DEBUG_KEYBOARD,
2379 "Leaving application keypad mode.\n");
2380 terminal->pvt->keypad_mode = VTE_KEYMODE_NORMAL;
2381 }
2382
2383 /* Same as cursor_character_absolute, not widely supported. */
2384 static void
vte_sequence_handler_character_position_absolute(VteTerminal * terminal,GValueArray * params)2385 vte_sequence_handler_character_position_absolute (VteTerminal *terminal, GValueArray *params)
2386 {
2387 vte_sequence_handler_cursor_character_absolute (terminal, params);
2388 }
2389
2390 /* Set certain terminal attributes. */
2391 static void
vte_sequence_handler_set_mode(VteTerminal * terminal,GValueArray * params)2392 vte_sequence_handler_set_mode (VteTerminal *terminal, GValueArray *params)
2393 {
2394 guint i;
2395 long setting;
2396 GValue *value;
2397 if ((params == NULL) || (params->n_values == 0)) {
2398 return;
2399 }
2400 for (i = 0; i < params->n_values; i++) {
2401 value = g_value_array_get_nth(params, i);
2402 if (!G_VALUE_HOLDS_LONG(value)) {
2403 continue;
2404 }
2405 setting = g_value_get_long(value);
2406 vte_sequence_handler_set_mode_internal(terminal, setting, TRUE);
2407 }
2408 }
2409
2410 /* Unset certain terminal attributes. */
2411 static void
vte_sequence_handler_reset_mode(VteTerminal * terminal,GValueArray * params)2412 vte_sequence_handler_reset_mode (VteTerminal *terminal, GValueArray *params)
2413 {
2414 guint i;
2415 long setting;
2416 GValue *value;
2417 if ((params == NULL) || (params->n_values == 0)) {
2418 return;
2419 }
2420 for (i = 0; i < params->n_values; i++) {
2421 value = g_value_array_get_nth(params, i);
2422 if (!G_VALUE_HOLDS_LONG(value)) {
2423 continue;
2424 }
2425 setting = g_value_get_long(value);
2426 vte_sequence_handler_set_mode_internal(terminal, setting, FALSE);
2427 }
2428 }
2429
2430 /* Set certain terminal attributes. */
2431 static void
vte_sequence_handler_decset(VteTerminal * terminal,GValueArray * params)2432 vte_sequence_handler_decset (VteTerminal *terminal, GValueArray *params)
2433 {
2434 GValue *value;
2435 long setting;
2436 guint i;
2437 if ((params == NULL) || (params->n_values == 0)) {
2438 return;
2439 }
2440 for (i = 0; i < params->n_values; i++) {
2441 value = g_value_array_get_nth(params, i);
2442 if (!G_VALUE_HOLDS_LONG(value)) {
2443 continue;
2444 }
2445 setting = g_value_get_long(value);
2446 vte_sequence_handler_decset_internal(terminal, setting, FALSE, FALSE, TRUE);
2447 }
2448 }
2449
2450 /* Unset certain terminal attributes. */
2451 static void
vte_sequence_handler_decreset(VteTerminal * terminal,GValueArray * params)2452 vte_sequence_handler_decreset (VteTerminal *terminal, GValueArray *params)
2453 {
2454 GValue *value;
2455 long setting;
2456 guint i;
2457 if ((params == NULL) || (params->n_values == 0)) {
2458 return;
2459 }
2460 for (i = 0; i < params->n_values; i++) {
2461 value = g_value_array_get_nth(params, i);
2462 if (!G_VALUE_HOLDS_LONG(value)) {
2463 continue;
2464 }
2465 setting = g_value_get_long(value);
2466 vte_sequence_handler_decset_internal(terminal, setting, FALSE, FALSE, FALSE);
2467 }
2468 }
2469
2470 /* Erase certain lines in the display. */
2471 static void
vte_sequence_handler_erase_in_display(VteTerminal * terminal,GValueArray * params)2472 vte_sequence_handler_erase_in_display (VteTerminal *terminal, GValueArray *params)
2473 {
2474 GValue *value;
2475 long param;
2476 guint i;
2477 /* The default parameter is 0. */
2478 param = 0;
2479 /* Pull out the first parameter. */
2480 for (i = 0; (params != NULL) && (i < params->n_values); i++) {
2481 value = g_value_array_get_nth(params, i);
2482 if (!G_VALUE_HOLDS_LONG(value)) {
2483 continue;
2484 }
2485 param = g_value_get_long(value);
2486 break;
2487 }
2488 /* Clear the right area. */
2489 switch (param) {
2490 case 0:
2491 /* Clear below the current line. */
2492 _vte_sequence_handler_cd (terminal, NULL);
2493 break;
2494 case 1:
2495 /* Clear above the current line. */
2496 _vte_terminal_clear_above_current (terminal);
2497 /* Clear everything to the left of the cursor, too. */
2498 /* FIXME: vttest. */
2499 _vte_sequence_handler_cb (terminal, NULL);
2500 break;
2501 case 2:
2502 /* Clear the entire screen. */
2503 _vte_terminal_clear_screen (terminal);
2504 break;
2505 case 3:
2506 /* Drop the scrollback. */
2507 _vte_terminal_drop_scrollback (terminal);
2508 break;
2509 default:
2510 break;
2511 }
2512 /* We've modified the display. Make a note of it. */
2513 terminal->pvt->text_deleted_flag = TRUE;
2514 }
2515
2516 /* Erase certain parts of the current line in the display. */
2517 static void
vte_sequence_handler_erase_in_line(VteTerminal * terminal,GValueArray * params)2518 vte_sequence_handler_erase_in_line (VteTerminal *terminal, GValueArray *params)
2519 {
2520 GValue *value;
2521 long param;
2522 guint i;
2523 /* The default parameter is 0. */
2524 param = 0;
2525 /* Pull out the first parameter. */
2526 for (i = 0; (params != NULL) && (i < params->n_values); i++) {
2527 value = g_value_array_get_nth(params, i);
2528 if (!G_VALUE_HOLDS_LONG(value)) {
2529 continue;
2530 }
2531 param = g_value_get_long(value);
2532 break;
2533 }
2534 /* Clear the right area. */
2535 switch (param) {
2536 case 0:
2537 /* Clear to end of the line. */
2538 _vte_sequence_handler_ce (terminal, NULL);
2539 break;
2540 case 1:
2541 /* Clear to start of the line. */
2542 _vte_sequence_handler_cb (terminal, NULL);
2543 break;
2544 case 2:
2545 /* Clear the entire line. */
2546 _vte_terminal_clear_current_line (terminal);
2547 break;
2548 default:
2549 break;
2550 }
2551 /* We've modified the display. Make a note of it. */
2552 terminal->pvt->text_deleted_flag = TRUE;
2553 }
2554
2555 /* Perform a full-bore reset. */
2556 static void
vte_sequence_handler_full_reset(VteTerminal * terminal,GValueArray * params)2557 vte_sequence_handler_full_reset (VteTerminal *terminal, GValueArray *params)
2558 {
2559 vte_terminal_reset(terminal, TRUE, TRUE);
2560 }
2561
2562 /* Insert a certain number of lines below the current cursor. */
2563 static void
vte_sequence_handler_insert_lines(VteTerminal * terminal,GValueArray * params)2564 vte_sequence_handler_insert_lines (VteTerminal *terminal, GValueArray *params)
2565 {
2566 GValue *value;
2567 VteScreen *screen;
2568 long param, end, row, i, limit;
2569 screen = terminal->pvt->screen;
2570 /* The default is one. */
2571 param = 1;
2572 /* Extract any parameters. */
2573 if ((params != NULL) && (params->n_values > 0)) {
2574 value = g_value_array_get_nth(params, 0);
2575 if (G_VALUE_HOLDS_LONG(value)) {
2576 param = g_value_get_long(value);
2577 }
2578 }
2579 /* Find the region we're messing with. */
2580 row = terminal->pvt->cursor.row;
2581 if (terminal->pvt->scrolling_restricted) {
2582 end = screen->insert_delta + terminal->pvt->scrolling_region.end;
2583 } else {
2584 end = screen->insert_delta + terminal->pvt->row_count - 1;
2585 }
2586
2587 /* Only allow to insert as many lines as there are between this row
2588 * and the end of the scrolling region. See bug #676090.
2589 */
2590 limit = end - row + 1;
2591 param = MIN (param, limit);
2592
2593 for (i = 0; i < param; i++) {
2594 /* Clear a line off the end of the region and add one to the
2595 * top of the region. */
2596 _vte_terminal_ring_remove (terminal, end);
2597 _vte_terminal_ring_insert (terminal, row, TRUE);
2598 }
2599 terminal->pvt->cursor.col = 0;
2600 /* Update the display. */
2601 _vte_terminal_scroll_region(terminal, row, end - row + 1, param);
2602 /* Adjust the scrollbars if necessary. */
2603 _vte_terminal_adjust_adjustments(terminal);
2604 /* We've modified the display. Make a note of it. */
2605 terminal->pvt->text_inserted_flag = TRUE;
2606 }
2607
2608 /* Delete certain lines from the scrolling region. */
2609 static void
vte_sequence_handler_delete_lines(VteTerminal * terminal,GValueArray * params)2610 vte_sequence_handler_delete_lines (VteTerminal *terminal, GValueArray *params)
2611 {
2612 GValue *value;
2613 VteScreen *screen;
2614 long param, end, row, i, limit;
2615
2616 screen = terminal->pvt->screen;
2617 /* The default is one. */
2618 param = 1;
2619 /* Extract any parameters. */
2620 if ((params != NULL) && (params->n_values > 0)) {
2621 value = g_value_array_get_nth(params, 0);
2622 if (G_VALUE_HOLDS_LONG(value)) {
2623 param = g_value_get_long(value);
2624 }
2625 }
2626 /* Find the region we're messing with. */
2627 row = terminal->pvt->cursor.row;
2628 if (terminal->pvt->scrolling_restricted) {
2629 end = screen->insert_delta + terminal->pvt->scrolling_region.end;
2630 } else {
2631 end = screen->insert_delta + terminal->pvt->row_count - 1;
2632 }
2633
2634 /* Only allow to delete as many lines as there are between this row
2635 * and the end of the scrolling region. See bug #676090.
2636 */
2637 limit = end - row + 1;
2638 param = MIN (param, limit);
2639
2640 /* Clear them from below the current cursor. */
2641 for (i = 0; i < param; i++) {
2642 /* Insert a line at the end of the region and remove one from
2643 * the top of the region. */
2644 _vte_terminal_ring_remove (terminal, row);
2645 _vte_terminal_ring_insert (terminal, end, TRUE);
2646 }
2647 terminal->pvt->cursor.col = 0;
2648 /* Update the display. */
2649 _vte_terminal_scroll_region(terminal, row, end - row + 1, -param);
2650 /* Adjust the scrollbars if necessary. */
2651 _vte_terminal_adjust_adjustments(terminal);
2652 /* We've modified the display. Make a note of it. */
2653 terminal->pvt->text_deleted_flag = TRUE;
2654 }
2655
2656 /* Device status reports. The possible reports are the cursor position and
2657 * whether or not we're okay. */
2658 static void
vte_sequence_handler_device_status_report(VteTerminal * terminal,GValueArray * params)2659 vte_sequence_handler_device_status_report (VteTerminal *terminal, GValueArray *params)
2660 {
2661 GValue *value;
2662 VteScreen *screen;
2663 long param, rowval, origin, rowmax;
2664 char buf[128];
2665
2666 screen = terminal->pvt->screen;
2667
2668 if ((params != NULL) && (params->n_values > 0)) {
2669 value = g_value_array_get_nth(params, 0);
2670 if (G_VALUE_HOLDS_LONG(value)) {
2671 param = g_value_get_long(value);
2672 switch (param) {
2673 case 5:
2674 /* Send a thumbs-up sequence. */
2675 vte_terminal_feed_child(terminal, _VTE_CAP_CSI "0n", -1);
2676 break;
2677 case 6:
2678 /* Send the cursor position. */
2679 if (terminal->pvt->origin_mode &&
2680 terminal->pvt->scrolling_restricted) {
2681 origin = terminal->pvt->scrolling_region.start;
2682 rowmax = terminal->pvt->scrolling_region.end;
2683 } else {
2684 origin = 0;
2685 rowmax = terminal->pvt->row_count - 1;
2686 }
2687 rowval = terminal->pvt->cursor.row - screen->insert_delta - origin;
2688 rowval = CLAMP(rowval, 0, rowmax);
2689 g_snprintf(buf, sizeof(buf),
2690 _VTE_CAP_CSI "%ld;%ldR",
2691 rowval + 1,
2692 CLAMP(terminal->pvt->cursor.col + 1,
2693 1, terminal->pvt->column_count));
2694 vte_terminal_feed_child(terminal, buf, -1);
2695 break;
2696 default:
2697 break;
2698 }
2699 }
2700 }
2701 }
2702
2703 /* DEC-style device status reports. */
2704 static void
vte_sequence_handler_dec_device_status_report(VteTerminal * terminal,GValueArray * params)2705 vte_sequence_handler_dec_device_status_report (VteTerminal *terminal, GValueArray *params)
2706 {
2707 GValue *value;
2708 VteScreen *screen;
2709 long param, rowval, origin, rowmax;
2710 char buf[128];
2711
2712 screen = terminal->pvt->screen;
2713
2714 if ((params != NULL) && (params->n_values > 0)) {
2715 value = g_value_array_get_nth(params, 0);
2716 if (G_VALUE_HOLDS_LONG(value)) {
2717 param = g_value_get_long(value);
2718 switch (param) {
2719 case 6:
2720 /* Send the cursor position. */
2721 if (terminal->pvt->origin_mode &&
2722 terminal->pvt->scrolling_restricted) {
2723 origin = terminal->pvt->scrolling_region.start;
2724 rowmax = terminal->pvt->scrolling_region.end;
2725 } else {
2726 origin = 0;
2727 rowmax = terminal->pvt->row_count - 1;
2728 }
2729 rowval = terminal->pvt->cursor.row - screen->insert_delta - origin;
2730 rowval = CLAMP(rowval, 0, rowmax);
2731 g_snprintf(buf, sizeof(buf),
2732 _VTE_CAP_CSI "?%ld;%ldR",
2733 rowval + 1,
2734 CLAMP(terminal->pvt->cursor.col + 1,
2735 1, terminal->pvt->column_count));
2736 vte_terminal_feed_child(terminal, buf, -1);
2737 break;
2738 case 15:
2739 /* Send printer status -- 10 = ready,
2740 * 11 = not ready. We don't print. */
2741 vte_terminal_feed_child(terminal, _VTE_CAP_CSI "?11n", -1);
2742 break;
2743 case 25:
2744 /* Send UDK status -- 20 = locked,
2745 * 21 = not locked. I don't even know what
2746 * that means, but punt anyway. */
2747 vte_terminal_feed_child(terminal, _VTE_CAP_CSI "?20n", -1);
2748 break;
2749 case 26:
2750 /* Send keyboard status. 50 = no locator. */
2751 vte_terminal_feed_child(terminal, _VTE_CAP_CSI "?50n", -1);
2752 break;
2753 default:
2754 break;
2755 }
2756 }
2757 }
2758 }
2759
2760 /* Restore a certain terminal attribute. */
2761 static void
vte_sequence_handler_restore_mode(VteTerminal * terminal,GValueArray * params)2762 vte_sequence_handler_restore_mode (VteTerminal *terminal, GValueArray *params)
2763 {
2764 GValue *value;
2765 long setting;
2766 guint i;
2767 if ((params == NULL) || (params->n_values == 0)) {
2768 return;
2769 }
2770 for (i = 0; i < params->n_values; i++) {
2771 value = g_value_array_get_nth(params, i);
2772 if (!G_VALUE_HOLDS_LONG(value)) {
2773 continue;
2774 }
2775 setting = g_value_get_long(value);
2776 vte_sequence_handler_decset_internal(terminal, setting, TRUE, FALSE, FALSE);
2777 }
2778 }
2779
2780 /* Save a certain terminal attribute. */
2781 static void
vte_sequence_handler_save_mode(VteTerminal * terminal,GValueArray * params)2782 vte_sequence_handler_save_mode (VteTerminal *terminal, GValueArray *params)
2783 {
2784 GValue *value;
2785 long setting;
2786 guint i;
2787 if ((params == NULL) || (params->n_values == 0)) {
2788 return;
2789 }
2790 for (i = 0; i < params->n_values; i++) {
2791 value = g_value_array_get_nth(params, i);
2792 if (!G_VALUE_HOLDS_LONG(value)) {
2793 continue;
2794 }
2795 setting = g_value_get_long(value);
2796 vte_sequence_handler_decset_internal(terminal, setting, FALSE, TRUE, FALSE);
2797 }
2798 }
2799
2800 /* Perform a screen alignment test -- fill all visible cells with the
2801 * letter "E". */
2802 static void
vte_sequence_handler_screen_alignment_test(VteTerminal * terminal,GValueArray * params)2803 vte_sequence_handler_screen_alignment_test (VteTerminal *terminal, GValueArray *params)
2804 {
2805 long row;
2806 VteRowData *rowdata;
2807 VteScreen *screen;
2808 VteCell cell;
2809
2810 screen = terminal->pvt->screen;
2811
2812 for (row = terminal->pvt->screen->insert_delta;
2813 row < terminal->pvt->screen->insert_delta + terminal->pvt->row_count;
2814 row++) {
2815 /* Find this row. */
2816 while (_vte_ring_next(screen->row_data) <= row)
2817 _vte_terminal_ring_append (terminal, FALSE);
2818 _vte_terminal_adjust_adjustments(terminal);
2819 rowdata = _vte_ring_index_writable (screen->row_data, row);
2820 g_assert(rowdata != NULL);
2821 /* Clear this row. */
2822 _vte_row_data_shrink (rowdata, 0);
2823
2824 _vte_terminal_emit_text_deleted(terminal);
2825 /* Fill this row. */
2826 cell.c = 'E';
2827 cell.attr = basic_cell.cell.attr;
2828 cell.attr.columns = 1;
2829 _vte_row_data_fill (rowdata, &cell, terminal->pvt->column_count);
2830 _vte_terminal_emit_text_inserted(terminal);
2831 }
2832 _vte_invalidate_all(terminal);
2833
2834 /* We modified the display, so make a note of it for completeness. */
2835 terminal->pvt->text_modified_flag = TRUE;
2836 }
2837
2838 /* DECSCUSR set cursor style */
2839 static void
vte_sequence_handler_set_cursor_style(VteTerminal * terminal,GValueArray * params)2840 vte_sequence_handler_set_cursor_style (VteTerminal *terminal, GValueArray *params)
2841 {
2842 long style;
2843
2844 if ((params == NULL) || (params->n_values > 1)) {
2845 return;
2846 }
2847
2848 if (params->n_values == 0) {
2849 /* no parameters means default (according to vt100.net) */
2850 style = VTE_CURSOR_STYLE_TERMINAL_DEFAULT;
2851 } else {
2852 GValue *value = g_value_array_get_nth(params, 0);
2853
2854 if (!G_VALUE_HOLDS_LONG(value)) {
2855 return;
2856 }
2857 style = g_value_get_long(value);
2858 if (style < 0 || style > 6) {
2859 return;
2860 }
2861 }
2862
2863 _vte_terminal_set_cursor_style(terminal, style);
2864 }
2865
2866 /* Perform a soft reset. */
2867 static void
vte_sequence_handler_soft_reset(VteTerminal * terminal,GValueArray * params)2868 vte_sequence_handler_soft_reset (VteTerminal *terminal, GValueArray *params)
2869 {
2870 vte_terminal_reset(terminal, FALSE, FALSE);
2871 }
2872
2873 /* Window manipulation control sequences. Most of these are considered
2874 * bad ideas, but they're implemented as signals which the application
2875 * is free to ignore, so they're harmless. Handle at most one action,
2876 * see bug 741402. */
2877 static void
vte_sequence_handler_window_manipulation(VteTerminal * terminal,GValueArray * params)2878 vte_sequence_handler_window_manipulation (VteTerminal *terminal, GValueArray *params)
2879 {
2880 GdkScreen *gscreen;
2881 GValue *value;
2882 GtkWidget *widget;
2883 char buf[128];
2884 long param, arg1, arg2;
2885 gint width, height;
2886 guint i;
2887
2888 widget = &terminal->widget;
2889
2890 if (params == NULL || params->n_values == 0) {
2891 return;
2892 }
2893 value = g_value_array_get_nth(params, 0);
2894 if (!G_VALUE_HOLDS_LONG(value)) {
2895 return;
2896 }
2897 param = g_value_get_long(value);
2898
2899 arg1 = arg2 = -1;
2900 if (params->n_values > 1) {
2901 value = g_value_array_get_nth(params, 1);
2902 if (G_VALUE_HOLDS_LONG(value)) {
2903 arg1 = g_value_get_long(value);
2904 }
2905 }
2906 if (params->n_values > 2) {
2907 value = g_value_array_get_nth(params, 2);
2908 if (G_VALUE_HOLDS_LONG(value)) {
2909 arg2 = g_value_get_long(value);
2910 }
2911 }
2912
2913 switch (param) {
2914 case 1:
2915 _vte_debug_print(VTE_DEBUG_PARSE,
2916 "Deiconifying window.\n");
2917 vte_terminal_emit_deiconify_window(terminal);
2918 break;
2919 case 2:
2920 _vte_debug_print(VTE_DEBUG_PARSE,
2921 "Iconifying window.\n");
2922 vte_terminal_emit_iconify_window(terminal);
2923 break;
2924 case 3:
2925 if ((arg1 != -1) && (arg2 != -1)) {
2926 _vte_debug_print(VTE_DEBUG_PARSE,
2927 "Moving window to "
2928 "%ld,%ld.\n", arg1, arg2);
2929 vte_terminal_emit_move_window(terminal,
2930 arg1, arg2);
2931 i += 2;
2932 }
2933 break;
2934 case 4:
2935 if ((arg1 != -1) && (arg2 != -1)) {
2936 _vte_debug_print(VTE_DEBUG_PARSE,
2937 "Resizing window "
2938 "(to %ldx%ld pixels, grid size %ldx%ld).\n",
2939 arg2, arg1,
2940 arg2 / terminal->pvt->char_width,
2941 arg1 / terminal->pvt->char_height);
2942 vte_terminal_emit_resize_window(terminal,
2943 arg2 / terminal->pvt->char_width,
2944 arg1 / terminal->pvt->char_height);
2945 i += 2;
2946 }
2947 break;
2948 case 5:
2949 _vte_debug_print(VTE_DEBUG_PARSE, "Raising window.\n");
2950 vte_terminal_emit_raise_window(terminal);
2951 break;
2952 case 6:
2953 _vte_debug_print(VTE_DEBUG_PARSE, "Lowering window.\n");
2954 vte_terminal_emit_lower_window(terminal);
2955 break;
2956 case 7:
2957 _vte_debug_print(VTE_DEBUG_PARSE,
2958 "Refreshing window.\n");
2959 _vte_invalidate_all(terminal);
2960 vte_terminal_emit_refresh_window(terminal);
2961 break;
2962 case 8:
2963 if ((arg1 != -1) && (arg2 != -1)) {
2964 _vte_debug_print(VTE_DEBUG_PARSE,
2965 "Resizing window "
2966 "(to %ld columns, %ld rows).\n",
2967 arg2, arg1);
2968 vte_terminal_emit_resize_window(terminal, arg2, arg1);
2969 i += 2;
2970 }
2971 break;
2972 case 9:
2973 switch (arg1) {
2974 case 0:
2975 _vte_debug_print(VTE_DEBUG_PARSE,
2976 "Restoring window.\n");
2977 vte_terminal_emit_restore_window(terminal);
2978 break;
2979 case 1:
2980 _vte_debug_print(VTE_DEBUG_PARSE,
2981 "Maximizing window.\n");
2982 vte_terminal_emit_maximize_window(terminal);
2983 break;
2984 default:
2985 break;
2986 }
2987 i++;
2988 break;
2989 case 11:
2990 /* If we're unmapped, then we're iconified. */
2991 g_snprintf(buf, sizeof(buf),
2992 _VTE_CAP_CSI "%dt",
2993 1 + !gtk_widget_get_mapped(widget));
2994 _vte_debug_print(VTE_DEBUG_PARSE,
2995 "Reporting window state %s.\n",
2996 gtk_widget_get_mapped(widget) ?
2997 "non-iconified" : "iconified");
2998 vte_terminal_feed_child(terminal, buf, -1);
2999 break;
3000 case 13:
3001 /* Send window location, in pixels. */
3002 gdk_window_get_origin(gtk_widget_get_window(widget),
3003 &width, &height);
3004 g_snprintf(buf, sizeof(buf),
3005 _VTE_CAP_CSI "3;%d;%dt",
3006 width + terminal->pvt->padding.left,
3007 height + terminal->pvt->padding.top);
3008 _vte_debug_print(VTE_DEBUG_PARSE,
3009 "Reporting window location"
3010 "(%d++,%d++).\n",
3011 width, height);
3012 vte_terminal_feed_child(terminal, buf, -1);
3013 break;
3014 case 14:
3015 /* Send window size, in pixels. */
3016 g_snprintf(buf, sizeof(buf),
3017 _VTE_CAP_CSI "4;%d;%dt",
3018 (int)(terminal->pvt->row_count * terminal->pvt->char_height),
3019 (int)(terminal->pvt->column_count * terminal->pvt->char_width));
3020 _vte_debug_print(VTE_DEBUG_PARSE,
3021 "Reporting window size "
3022 "(%dx%d)\n",
3023 (int)(terminal->pvt->row_count * terminal->pvt->char_height),
3024 (int)(terminal->pvt->column_count * terminal->pvt->char_width));
3025
3026 vte_terminal_feed_child(terminal, buf, -1);
3027 break;
3028 case 18:
3029 /* Send widget size, in cells. */
3030 _vte_debug_print(VTE_DEBUG_PARSE,
3031 "Reporting widget size.\n");
3032 g_snprintf(buf, sizeof(buf),
3033 _VTE_CAP_CSI "8;%ld;%ldt",
3034 terminal->pvt->row_count,
3035 terminal->pvt->column_count);
3036 vte_terminal_feed_child(terminal, buf, -1);
3037 break;
3038 case 19:
3039 _vte_debug_print(VTE_DEBUG_PARSE,
3040 "Reporting screen size.\n");
3041 gscreen = gtk_widget_get_screen(widget);
3042 height = gdk_screen_get_height(gscreen);
3043 width = gdk_screen_get_width(gscreen);
3044 g_snprintf(buf, sizeof(buf),
3045 _VTE_CAP_CSI "9;%ld;%ldt",
3046 height / terminal->pvt->char_height,
3047 width / terminal->pvt->char_width);
3048 vte_terminal_feed_child(terminal, buf, -1);
3049 break;
3050 case 20:
3051 /* Report a static icon title, since the real
3052 icon title should NEVER be reported, as it
3053 creates a security vulnerability. See
3054 http://marc.info/?l=bugtraq&m=104612710031920&w=2
3055 and CVE-2003-0070. */
3056 _vte_debug_print(VTE_DEBUG_PARSE,
3057 "Reporting fake icon title.\n");
3058 /* never use terminal->pvt->icon_title here! */
3059 g_snprintf (buf, sizeof (buf),
3060 _VTE_CAP_OSC "LTerminal" _VTE_CAP_ST);
3061 vte_terminal_feed_child(terminal, buf, -1);
3062 break;
3063 case 21:
3064 /* Report a static window title, since the real
3065 window title should NEVER be reported, as it
3066 creates a security vulnerability. See
3067 http://marc.info/?l=bugtraq&m=104612710031920&w=2
3068 and CVE-2003-0070. */
3069 _vte_debug_print(VTE_DEBUG_PARSE,
3070 "Reporting fake window title.\n");
3071 /* never use terminal->pvt->window_title here! */
3072 g_snprintf (buf, sizeof (buf),
3073 _VTE_CAP_OSC "lTerminal" _VTE_CAP_ST);
3074 vte_terminal_feed_child(terminal, buf, -1);
3075 break;
3076 default:
3077 if (param >= 24) {
3078 _vte_debug_print(VTE_DEBUG_PARSE,
3079 "Resizing to %ld rows.\n",
3080 param);
3081 /* Resize to the specified number of
3082 * rows. */
3083 vte_terminal_emit_resize_window(terminal,
3084 terminal->pvt->column_count,
3085 param);
3086 }
3087 break;
3088 }
3089 }
3090
3091 /* Internal helper for setting/querying special colors */
3092 static void
vte_sequence_handler_change_special_color_internal(VteTerminal * terminal,GValueArray * params,int index,int index_fallback,int osc,const char * terminator)3093 vte_sequence_handler_change_special_color_internal (VteTerminal *terminal, GValueArray *params,
3094 int index, int index_fallback, int osc,
3095 const char *terminator)
3096 {
3097 gchar *name = NULL;
3098 GValue *value;
3099 PangoColor color;
3100
3101 if (params != NULL && params->n_values > 0) {
3102 value = g_value_array_get_nth (params, 0);
3103
3104 if (G_VALUE_HOLDS_STRING (value))
3105 name = g_value_dup_string (value);
3106 else if (G_VALUE_HOLDS_POINTER (value))
3107 name = vte_ucs4_to_utf8 (terminal, g_value_get_pointer (value));
3108
3109 if (! name)
3110 return;
3111
3112 if (vte_parse_color (name, &color))
3113 _vte_terminal_set_color_internal(terminal, index, VTE_COLOR_SOURCE_ESCAPE, &color);
3114 else if (strcmp (name, "?") == 0) {
3115 gchar buf[128];
3116 PangoColor *c = _vte_terminal_get_color(terminal, index);
3117 if (c == NULL && index_fallback != -1)
3118 c = _vte_terminal_get_color(terminal, index_fallback);
3119 g_assert(c != NULL);
3120 g_snprintf (buf, sizeof (buf),
3121 _VTE_CAP_OSC "%d;rgb:%04x/%04x/%04x%s",
3122 osc, c->red, c->green, c->blue, terminator);
3123 vte_terminal_feed_child (terminal, buf, -1);
3124 }
3125
3126 g_free (name);
3127 }
3128 }
3129
3130 /* Change the default foreground cursor, BEL terminated */
3131 static void
vte_sequence_handler_change_foreground_color_bel(VteTerminal * terminal,GValueArray * params)3132 vte_sequence_handler_change_foreground_color_bel (VteTerminal *terminal, GValueArray *params)
3133 {
3134 vte_sequence_handler_change_special_color_internal (terminal, params,
3135 VTE_DEFAULT_FG, -1, 10, BEL);
3136 }
3137
3138 /* Change the default foreground cursor, ST terminated */
3139 static void
vte_sequence_handler_change_foreground_color_st(VteTerminal * terminal,GValueArray * params)3140 vte_sequence_handler_change_foreground_color_st (VteTerminal *terminal, GValueArray *params)
3141 {
3142 vte_sequence_handler_change_special_color_internal (terminal, params,
3143 VTE_DEFAULT_FG, -1, 10, ST);
3144 }
3145
3146 /* Reset the default foreground color */
3147 static void
vte_sequence_handler_reset_foreground_color(VteTerminal * terminal,GValueArray * params)3148 vte_sequence_handler_reset_foreground_color (VteTerminal *terminal, GValueArray *params)
3149 {
3150 _vte_terminal_set_color_internal(terminal, VTE_DEFAULT_FG, VTE_COLOR_SOURCE_ESCAPE, NULL);
3151 }
3152
3153 /* Change the default background cursor, BEL terminated */
3154 static void
vte_sequence_handler_change_background_color_bel(VteTerminal * terminal,GValueArray * params)3155 vte_sequence_handler_change_background_color_bel (VteTerminal *terminal, GValueArray *params)
3156 {
3157 vte_sequence_handler_change_special_color_internal (terminal, params,
3158 VTE_DEFAULT_BG, -1, 11, BEL);
3159 }
3160
3161 /* Change the default background cursor, ST terminated */
3162 static void
vte_sequence_handler_change_background_color_st(VteTerminal * terminal,GValueArray * params)3163 vte_sequence_handler_change_background_color_st (VteTerminal *terminal, GValueArray *params)
3164 {
3165 vte_sequence_handler_change_special_color_internal (terminal, params,
3166 VTE_DEFAULT_BG, -1, 11, ST);
3167 }
3168
3169 /* Reset the default background color */
3170 static void
vte_sequence_handler_reset_background_color(VteTerminal * terminal,GValueArray * params)3171 vte_sequence_handler_reset_background_color (VteTerminal *terminal, GValueArray *params)
3172 {
3173 _vte_terminal_set_color_internal(terminal, VTE_DEFAULT_BG, VTE_COLOR_SOURCE_ESCAPE, NULL);
3174 }
3175
3176 /* Change the color of the cursor, BEL terminated */
3177 static void
vte_sequence_handler_change_cursor_color_bel(VteTerminal * terminal,GValueArray * params)3178 vte_sequence_handler_change_cursor_color_bel (VteTerminal *terminal, GValueArray *params)
3179 {
3180 vte_sequence_handler_change_special_color_internal (terminal, params,
3181 VTE_CURSOR_BG, VTE_DEFAULT_FG, 12, BEL);
3182 }
3183
3184 /* Change the color of the cursor, ST terminated */
3185 static void
vte_sequence_handler_change_cursor_color_st(VteTerminal * terminal,GValueArray * params)3186 vte_sequence_handler_change_cursor_color_st (VteTerminal *terminal, GValueArray *params)
3187 {
3188 vte_sequence_handler_change_special_color_internal (terminal, params,
3189 VTE_CURSOR_BG, VTE_DEFAULT_FG, 12, ST);
3190 }
3191
3192 /* Reset the color of the cursor */
3193 static void
vte_sequence_handler_reset_cursor_color(VteTerminal * terminal,GValueArray * params)3194 vte_sequence_handler_reset_cursor_color (VteTerminal *terminal, GValueArray *params)
3195 {
3196 _vte_terminal_set_color_internal(terminal, VTE_CURSOR_BG, VTE_COLOR_SOURCE_ESCAPE, NULL);
3197 }
3198
3199 /* Change the highlight background color, BEL terminated */
3200 static void
vte_sequence_handler_change_highlight_background_color_bel(VteTerminal * terminal,GValueArray * params)3201 vte_sequence_handler_change_highlight_background_color_bel (VteTerminal *terminal, GValueArray *params)
3202 {
3203 vte_sequence_handler_change_special_color_internal (terminal, params,
3204 VTE_HIGHLIGHT_BG, VTE_DEFAULT_FG, 17, BEL);
3205 }
3206
3207 /* Change the highlight background color, ST terminated */
3208 static void
vte_sequence_handler_change_highlight_background_color_st(VteTerminal * terminal,GValueArray * params)3209 vte_sequence_handler_change_highlight_background_color_st (VteTerminal *terminal, GValueArray *params)
3210 {
3211 vte_sequence_handler_change_special_color_internal (terminal, params,
3212 VTE_HIGHLIGHT_BG, VTE_DEFAULT_FG, 17, ST);
3213 }
3214
3215 /* Reset the highlight background color */
3216 static void
vte_sequence_handler_reset_highlight_background_color(VteTerminal * terminal,GValueArray * params)3217 vte_sequence_handler_reset_highlight_background_color (VteTerminal *terminal, GValueArray *params)
3218 {
3219 _vte_terminal_set_color_internal(terminal, VTE_HIGHLIGHT_BG, VTE_COLOR_SOURCE_ESCAPE, NULL);
3220 }
3221
3222 /* Change the highlight foreground color, BEL terminated */
3223 static void
vte_sequence_handler_change_highlight_foreground_color_bel(VteTerminal * terminal,GValueArray * params)3224 vte_sequence_handler_change_highlight_foreground_color_bel (VteTerminal *terminal, GValueArray *params)
3225 {
3226 vte_sequence_handler_change_special_color_internal (terminal, params,
3227 VTE_HIGHLIGHT_FG, VTE_DEFAULT_BG, 19, BEL);
3228 }
3229
3230 /* Change the highlight foreground color, ST terminated */
3231 static void
vte_sequence_handler_change_highlight_foreground_color_st(VteTerminal * terminal,GValueArray * params)3232 vte_sequence_handler_change_highlight_foreground_color_st (VteTerminal *terminal, GValueArray *params)
3233 {
3234 vte_sequence_handler_change_special_color_internal (terminal, params,
3235 VTE_HIGHLIGHT_FG, VTE_DEFAULT_BG, 19, ST);
3236 }
3237
3238 /* Reset the highlight foreground color */
3239 static void
vte_sequence_handler_reset_highlight_foreground_color(VteTerminal * terminal,GValueArray * params)3240 vte_sequence_handler_reset_highlight_foreground_color (VteTerminal *terminal, GValueArray *params)
3241 {
3242 _vte_terminal_set_color_internal(terminal, VTE_HIGHLIGHT_FG, VTE_COLOR_SOURCE_ESCAPE, NULL);
3243 }
3244
3245
3246 /* Lookup tables */
3247
3248 #define VTE_SEQUENCE_HANDLER(name) name
3249
3250 static const struct vteseq_n_struct *
3251 vteseq_n_lookup (register const char *str, register unsigned int len);
3252 #include"vteseq-n.c"
3253
3254 #undef VTE_SEQUENCE_HANDLER
3255
3256 static VteTerminalSequenceHandler
_vte_sequence_get_handler(const char * name)3257 _vte_sequence_get_handler (const char *name)
3258 {
3259 int len = strlen (name);
3260
3261 if (G_UNLIKELY (len < 2)) {
3262 return NULL;
3263 } else {
3264 const struct vteseq_n_struct *seqhandler;
3265 seqhandler = vteseq_n_lookup (name, len);
3266 return seqhandler ? seqhandler->handler : NULL;
3267 }
3268 }
3269
3270
3271 /* Handle a terminal control sequence and its parameters. */
3272 void
_vte_terminal_handle_sequence(VteTerminal * terminal,const char * match,GValueArray * params)3273 _vte_terminal_handle_sequence(VteTerminal *terminal,
3274 const char *match,
3275 GValueArray *params)
3276 {
3277 VteTerminalSequenceHandler handler;
3278
3279 _VTE_DEBUG_IF(VTE_DEBUG_PARSE)
3280 display_control_sequence(match, params);
3281
3282 /* Find the handler for this control sequence. */
3283 handler = _vte_sequence_get_handler (match);
3284
3285 if (handler != NULL) {
3286 /* Let the handler handle it. */
3287 handler (terminal, params);
3288 } else {
3289 _vte_debug_print (VTE_DEBUG_MISC,
3290 "No handler for control sequence `%s' defined.\n",
3291 match);
3292 }
3293 }
3294