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