Fix hiliting of matched strings to better match the returned matched
[vte.git] / src / vte.c
1 /*
2  * Copyright (C) 2001,2002 Red Hat, Inc.
3  *
4  * This is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Library General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #ident "$Id$"
20 #include "../config.h"
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/param.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <iconv.h>
29 #include <langinfo.h>
30 #include <math.h>
31 #include <pwd.h>
32 #include <regex.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <termios.h>
38 #include <unistd.h>
39 #include <wchar.h>
40 #include <wctype.h>
41 #include <glib.h>
42 #include <glib-object.h>
43 #include <gdk/gdk.h>
44 #include <gdk/gdkkeysyms.h>
45 #include <gdk/gdkx.h>
46 #include <gtk/gtk.h>
47 #include <pango/pango.h>
48 #include <pango/pangox.h>
49 #include "caps.h"
50 #include "debug.h"
51 #include "marshal.h"
52 #include "pty.h"
53 #include "termcap.h"
54 #include "ring.h"
55 #include "trie.h"
56 #include "vte.h"
57 #include "vteaccess.h"
58 #include <X11/Xlib.h>
59 #ifdef HAVE_XFT
60 #include <X11/extensions/Xrender.h>
61 #include <X11/Xft/Xft.h>
62 #endif
63
64 #define VTE_TAB_WIDTH   8
65 #define VTE_LINE_WIDTH  1
66 #define VTE_DEF_FG      16
67 #define VTE_DEF_BG      17
68 #define VTE_SATURATION_MAX 10000
69 #define VTE_SCROLLBACK_MIN 100
70 #define VTE_DEFAULT_EMULATION "xterm"
71 #define VTE_DEFAULT_CURSOR GDK_XTERM
72 #define VTE_MOUSING_CURSOR GDK_LEFT_PTR
73 #define VTE_TAB_MAX     999
74
75 /* The structure we use to hold characters we're supposed to display -- this
76  * includes any supported visible attributes. */
77 struct vte_charcell {
78         wchar_t c;              /* The wide character. */
79         guint16 columns: 2;     /* Number of visible columns (as determined
80                                    by wcwidth(c)). */
81         guint16 fore: 5;        /* Indices in the color palette for the */
82         guint16 back: 5;        /* foreground and background of the cell. */
83         guint16 standout: 1;    /* Single-bit attributes. */
84         guint16 underline: 1;
85         guint16 reverse: 1;
86         guint16 blink: 1;
87         guint16 half: 1;
88         guint16 bold: 1;
89         guint16 invisible: 1;
90         guint16 protect: 1;
91         guint16 alternate: 1;
92 };
93
94 /* A match regex, with a tag. */
95 struct vte_match_regex {
96         regex_t reg;
97         gint tag;
98 };
99
100 /* The terminal's keypad state.  A terminal can either be using the normal
101  * keypad, or the "application" keypad.  Arrow key sequences, for example,
102  * are really only defined for "application" mode. */
103 typedef enum {
104         VTE_KEYPAD_NORMAL,
105         VTE_KEYPAD_APPLICATION,
106 } VteKeypad;
107
108 typedef struct _VteScreen VteScreen;
109
110 typedef struct _VteWordCharRange {
111         wchar_t start, end;
112 } VteWordCharRange;
113
114 /* Terminal private data. */
115 struct _VteTerminalPrivate {
116         /* Emulation setup data. */
117         struct vte_termcap *termcap;    /* termcap storage */
118         struct vte_trie *trie;          /* control sequence trie */
119         const char *termcap_path;       /* path to termcap file */
120         const char *terminal;           /* terminal type to emulate */
121         GTree *sequences;               /* sequence handlers, keyed by GQuark
122                                            based on the sequence name */
123         struct {                        /* boolean termcap flags */
124                 gboolean am;
125                 gboolean bw;
126                 gboolean ul;
127         } flags;
128
129         /* PTY handling data. */
130         const char *shell;              /* shell we started */
131         int pty_master;                 /* pty master descriptor */
132         GIOChannel *pty_input;          /* master input watch */
133         int pty_input_tag;
134         GIOChannel *pty_output;         /* master output watch */
135         int pty_output_tag;
136         pid_t pty_pid;                  /* pid of child using pty slave */
137         const char *encoding;           /* the pty's encoding */
138         const char *gxencoding[4];      /* alternate encodings */
139
140         /* Input data queues. */
141         iconv_t incoming_conv;          /* narrow/wide conversion state */
142         unsigned char *incoming;        /* pending output characters */
143         size_t n_incoming;
144         gboolean processing;
145         guint processing_tag;
146
147         /* Output data queue. */
148         unsigned char *outgoing;        /* pending input characters */
149         size_t n_outgoing;
150         iconv_t outgoing_conv_wide;
151         iconv_t outgoing_conv_utf8;
152
153         /* Data used when rendering the text. */
154         struct {
155                 guint16 red, green, blue;
156                 unsigned long pixel;
157 #ifdef HAVE_XFT
158                 XRenderColor rcolor;
159                 XftColor ftcolor;
160 #endif
161         } palette[18];
162         XFontSet fontset;
163 #ifdef HAVE_XFT
164         XftFont *ftfont;
165 #endif
166         gboolean use_xft;
167         PangoFontDescription *fontdesc;
168         PangoLayout *layout;
169         gboolean use_pango;
170
171         /* Emulation state. */
172         int keypad;
173
174         /* Screen data.  We support the normal screen, and an alternate
175          * screen, which seems to be a DEC-specific feature. */
176         struct _VteScreen {
177                 VteRing *row_data;      /* row data, arranged as a GArray of
178                                            vte_charcell structures */
179                 struct {
180                         long row, col;
181                 } cursor_current, cursor_saved;
182                                         /* the current and saved positions of
183                                            the [insertion] cursor */
184                 gboolean cursor_visible;
185                 gboolean reverse_mode;  /* reverse mode */
186                 gboolean insert_mode;   /* insert mode */
187                 struct {
188                         int start, end;
189                 } scrolling_region;     /* the region we scroll in */
190                 gboolean scrolling_restricted;
191                 long scroll_delta;      /* scroll offset */
192                 long insert_delta;      /* insertion offset */
193                 struct vte_charcell defaults;   /* default characteristics
194                                                    for insertion of any new
195                                                    characters */
196         } normal_screen, alternate_screen, *screen;
197
198         /* Saved settings. */
199         GHashTable *dec_saved;
200
201         /* Selection information. */
202         gboolean has_selection;
203         char *selection;
204         enum {
205                 selection_type_char,
206                 selection_type_word,
207                 selection_type_line,
208         } selection_type;
209         struct {
210                 double x, y;
211         } selection_origin, selection_last;
212         struct {
213                 long x, y;
214         } selection_start, selection_end;
215
216         /* Miscellaneous options. */
217         GArray *word_chars;
218         VteTerminalEraseBinding backspace_binding, delete_binding;
219         gboolean alt_sends_escape;
220         gboolean audible_bell;
221         gboolean xterm_font_tweak;
222         GHashTable *tabstops;
223
224         /* Scrolling options. */
225         gboolean scroll_on_output;
226         gboolean scroll_on_keystroke;
227         long scrollback_lines;
228
229         /* Cursor blinking. */
230         gboolean cursor_blinks;
231         gint cursor_blink_tag;
232
233         /* Background images/"transparency". */
234         gboolean bg_transparent;
235         gboolean bg_transparent_update_pending;
236         guint bg_transparent_update_tag;
237         GdkAtom bg_transparent_atom;
238         GdkWindow *bg_transparent_window;
239         GdkPixbuf *bg_transparent_image;
240         GdkPixbuf *bg_image;
241         GtkWidget *bg_toplevel;
242         long bg_saturation;     /* out of VTE_SATURATION_MAX */
243
244         /* Input method support. */
245         GtkIMContext *im_context;
246         char *im_preedit;
247         int im_preedit_cursor;
248
249         /* Input device options. */
250         guint last_keypress_time;
251         gboolean mouse_send_xy_on_click;
252         gboolean mouse_send_xy_on_button;
253         gboolean mouse_hilite_tracking;
254         gboolean mouse_cell_motion_tracking;
255         gboolean mouse_all_motion_tracking;
256         GdkCursor *mouse_default_cursor,
257                   *mouse_mousing_cursor,
258                   *mouse_inviso_cursor;
259         guint mouse_last_button;
260         gdouble mouse_last_x, mouse_last_y;
261         gboolean mouse_autohide;
262
263         /* State variables for handling match checks. */
264         char *match_contents;
265         GArray *match_attributes;
266         GArray *match_regexes;
267         struct {
268                 long row, column;
269         } match_start, match_end;
270 };
271
272 /* A function which can handle a terminal control sequence. */
273 typedef void (*VteTerminalSequenceHandler)(VteTerminal *terminal,
274                                            const char *match,
275                                            GQuark match_quark,
276                                            GValueArray *params);
277 static void vte_terminal_ensure_cursor(VteTerminal *terminal);
278 static void vte_terminal_insert_char(GtkWidget *widget, wchar_t c,
279                                      gboolean force_insert);
280 static void vte_sequence_handler_clear_screen(VteTerminal *terminal,
281                                               const char *match,
282                                               GQuark match_quark,
283                                               GValueArray *params);
284 static void vte_sequence_handler_do(VteTerminal *terminal,
285                                     const char *match,
286                                     GQuark match_quark,
287                                     GValueArray *params);
288 static void vte_sequence_handler_ho(VteTerminal *terminal,
289                                     const char *match,
290                                     GQuark match_quark,
291                                     GValueArray *params);
292 static void vte_sequence_handler_nd(VteTerminal *terminal,
293                                     const char *match,
294                                     GQuark match_quark,
295                                     GValueArray *params);
296 static void vte_sequence_handler_ue(VteTerminal *terminal,
297                                     const char *match,
298                                     GQuark match_quark,
299                                     GValueArray *params);
300 static void vte_sequence_handler_up(VteTerminal *terminal,
301                                     const char *match,
302                                     GQuark match_quark,
303                                     GValueArray *params);
304 static void vte_sequence_handler_us(VteTerminal *terminal,
305                                     const char *match,
306                                     GQuark match_quark,
307                                     GValueArray *params);
308 static void vte_sequence_handler_vb(VteTerminal *terminal,
309                                     const char *match,
310                                     GQuark match_quark,
311                                     GValueArray *params);
312 static gboolean vte_terminal_io_read(GIOChannel *channel,
313                                      GdkInputCondition condition,
314                                      gpointer data);
315 static gboolean vte_terminal_io_write(GIOChannel *channel,
316                                       GdkInputCondition condition,
317                                       gpointer data);
318 static GdkFilterReturn vte_terminal_filter_property_changes(GdkXEvent *xevent,
319                                                             GdkEvent *event,
320                                                             gpointer data);
321 static void vte_terminal_match_hilite_clear(VteTerminal *terminal);
322 static void vte_terminal_queue_background_update(VteTerminal *terminal);
323
324 /* Free a no-longer-used row data array. */
325 static void
326 vte_free_row_data(gpointer freeing, gpointer data)
327 {
328         if (freeing) {
329                 g_array_free((GArray*)freeing, FALSE);
330         }
331 }
332
333 /* Allocate a new line. */
334 static GArray *
335 vte_new_row_data(void)
336 {
337         return g_array_new(FALSE, FALSE, sizeof(struct vte_charcell));
338 }
339
340 /* Reset defaults for character insertion. */
341 static void
342 vte_terminal_set_default_attributes(VteTerminal *terminal)
343 {
344         g_return_if_fail(VTE_IS_TERMINAL(terminal));
345         terminal->pvt->screen->defaults.c = 0;
346         terminal->pvt->screen->defaults.columns = 1;
347         terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
348         terminal->pvt->screen->defaults.back = VTE_DEF_BG;
349         terminal->pvt->screen->defaults.reverse = 0;
350         terminal->pvt->screen->defaults.bold = 0;
351         terminal->pvt->screen->defaults.invisible = 0;
352         terminal->pvt->screen->defaults.protect = 0;
353         terminal->pvt->screen->defaults.standout = 0;
354         terminal->pvt->screen->defaults.underline = 0;
355         terminal->pvt->screen->defaults.half = 0;
356         terminal->pvt->screen->defaults.blink = 0;
357         /* Alternate charset isn't an attribute, though we treat it as one.
358          * terminal->pvt->screen->defaults.alternate = 0; */
359 }
360
361 /* Cause certain cells to be updated. */
362 static void
363 vte_invalidate_cells(VteTerminal *terminal,
364                      glong column_start, gint column_count,
365                      glong row_start, gint row_count)
366 {
367         GdkRectangle rect;
368         GtkWidget *widget;
369
370         g_return_if_fail(VTE_IS_TERMINAL(terminal));
371         widget = GTK_WIDGET(terminal);
372         if (!GTK_WIDGET_REALIZED(widget)) {
373                 return;
374         }
375
376         /* Subtract the scrolling offset from the row start so that the
377          * resulting rectangle is relative to the visible portion of the
378          * buffer. */
379         row_start -= terminal->pvt->screen->scroll_delta;
380
381         /* Clamp the start values to reasonable numbers. */
382         column_start = (column_start > 0) ? column_start : 0;
383         row_start = (row_start > 0) ? row_start : 0;
384
385         /* Convert the column and row start and end to pixel values
386          * by multiplying by the size of a character cell. */
387         rect.x = column_start * terminal->char_width;
388         rect.width = column_count * terminal->char_width;
389         rect.y = row_start * terminal->char_height;
390         rect.height = row_count * terminal->char_height;
391
392         /* Invalidate the rectangle. */
393         gdk_window_invalidate_rect(widget->window, &rect, TRUE);
394 }
395
396 /* Redraw the entire window. */
397 static void
398 vte_invalidate_all(VteTerminal *terminal)
399 {
400         g_return_if_fail(VTE_IS_TERMINAL(terminal));
401         if (!GTK_IS_WIDGET(terminal) ||
402             !GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
403                 return;
404         }
405         vte_invalidate_cells(terminal,
406                              0, terminal->column_count,
407                              terminal->pvt->screen->scroll_delta,
408                              terminal->row_count);
409 }
410
411 /* Find the character in the given "virtual" position. */
412 static struct vte_charcell *
413 vte_terminal_find_charcell(VteTerminal *terminal, long col, long row)
414 {
415         GArray *rowdata;
416         struct vte_charcell *ret = NULL;
417         VteScreen *screen;
418         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
419         screen = terminal->pvt->screen;
420         if (vte_ring_contains(screen->row_data, row)) {
421                 rowdata = vte_ring_index(screen->row_data, GArray*, row);
422                 if (rowdata->len > col) {
423                         ret = &g_array_index(rowdata, struct vte_charcell, col);
424                 }
425         }
426         return ret;
427 }
428
429 /* Cause the cursor to be redrawn. */
430 static void
431 vte_invalidate_cursor_once(gpointer data)
432 {
433         VteTerminal *terminal;
434         VteScreen *screen;
435         struct vte_charcell *cell;
436         size_t preedit_length;
437         int columns;
438
439         if (!VTE_IS_TERMINAL(data)) {
440                 return;
441         }
442         terminal = VTE_TERMINAL(data);
443
444         if (GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
445                 if (terminal->pvt->im_preedit != NULL) {
446                         preedit_length = strlen(terminal->pvt->im_preedit);
447                 } else {
448                         preedit_length = 0;
449                 }
450
451                 screen = terminal->pvt->screen;
452                 columns = 1;
453                 cell = vte_terminal_find_charcell(terminal,
454                                                   screen->cursor_current.col,
455                                                   screen->cursor_current.row);
456                 if (cell != NULL) {
457                         columns = cell->columns;
458                 }
459
460                 vte_invalidate_cells(terminal,
461                                      screen->cursor_current.col,
462                                      columns + preedit_length,
463                                      screen->cursor_current.row,
464                                      1);
465 #ifdef VTE_DEBUG
466                 if (vte_debug_on(VTE_DEBUG_UPDATES)) {
467                         fprintf(stderr, "Invalidating cursor at (%ld,%ld-%ld)."
468                                 "\n", screen->cursor_current.row,
469                                 screen->cursor_current.col,
470                                 screen->cursor_current.col +
471                                 columns + preedit_length);
472                 }
473 #endif
474         }
475 }
476
477 /* Invalidate the cursor repeatedly. */
478 static gboolean
479 vte_invalidate_cursor_periodic(gpointer data)
480 {
481         VteTerminal *terminal;
482         GtkSettings *settings;
483         gint blink_cycle = 1000;
484
485         g_return_val_if_fail(VTE_IS_TERMINAL(data), FALSE);
486         if (!GTK_WIDGET_REALIZED(GTK_WIDGET(data))) {
487                 return TRUE;
488         }
489
490         terminal = VTE_TERMINAL(data);
491         vte_invalidate_cursor_once(data);
492
493         settings = gtk_widget_get_settings(GTK_WIDGET(data));
494         if (G_IS_OBJECT(settings)) {
495                 g_object_get(G_OBJECT(settings), "gtk-cursor-blink-time",
496                              &blink_cycle, NULL);
497         }
498
499         terminal->pvt->cursor_blink_tag = g_timeout_add(blink_cycle / 2,
500                                                         vte_invalidate_cursor_periodic,
501                                                         terminal);
502
503         return FALSE;
504 }
505
506 /* Emit a "selection_changed" signal. */
507 static void
508 vte_terminal_emit_selection_changed(VteTerminal *terminal)
509 {
510         g_signal_emit_by_name(terminal, "selection-changed");
511 }
512
513 /* Emit a "contents_changed" signal. */
514 static void
515 vte_terminal_emit_contents_changed(VteTerminal *terminal)
516 {
517         g_signal_emit_by_name(terminal, "contents-changed");
518 }
519
520 /* Emit a "cursor_moved" signal. */
521 static void
522 vte_terminal_emit_cursor_moved(VteTerminal *terminal)
523 {
524         g_signal_emit_by_name(terminal, "cursor-moved");
525 }
526
527 /* Emit an "icon-title-changed" signal. */
528 static void
529 vte_terminal_emit_icon_title_changed(VteTerminal *terminal)
530 {
531         g_signal_emit_by_name(terminal, "icon-title-changed");
532 }
533
534 /* Emit a "window-title-changed" signal. */
535 static void
536 vte_terminal_emit_window_title_changed(VteTerminal *terminal)
537 {
538         g_signal_emit_by_name(terminal, "window-title-changed");
539 }
540
541 /* Emit a "deiconify-window" signal. */
542 static void
543 vte_terminal_emit_deiconify_window(VteTerminal *terminal)
544 {
545         g_signal_emit_by_name(terminal, "deiconify-window");
546 }
547
548 /* Emit a "iconify-window" signal. */
549 static void
550 vte_terminal_emit_iconify_window(VteTerminal *terminal)
551 {
552         g_signal_emit_by_name(terminal, "iconify-window");
553 }
554
555 /* Emit a "raise-window" signal. */
556 static void
557 vte_terminal_emit_raise_window(VteTerminal *terminal)
558 {
559         g_signal_emit_by_name(terminal, "raise-window");
560 }
561
562 /* Emit a "lower-window" signal. */
563 static void
564 vte_terminal_emit_lower_window(VteTerminal *terminal)
565 {
566         g_signal_emit_by_name(terminal, "lower-window");
567 }
568
569 /* Emit a "maximize-window" signal. */
570 static void
571 vte_terminal_emit_maximize_window(VteTerminal *terminal)
572 {
573         g_signal_emit_by_name(terminal, "maximize-window");
574 }
575
576 /* Emit a "refresh-window" signal. */
577 static void
578 vte_terminal_emit_refresh_window(VteTerminal *terminal)
579 {
580         g_signal_emit_by_name(terminal, "refresh-window");
581 }
582
583 /* Emit a "restore-window" signal. */
584 static void
585 vte_terminal_emit_restore_window(VteTerminal *terminal)
586 {
587         g_signal_emit_by_name(terminal, "restore-window");
588 }
589
590 /* Emit a "eof" signal. */
591 static void
592 vte_terminal_emit_eof(VteTerminal *terminal)
593 {
594         g_signal_emit_by_name(terminal, "eof");
595 }
596
597 /* Emit a "char-size-changed" signal. */
598 static void
599 vte_terminal_emit_char_size_changed(VteTerminal *terminal,
600                                     guint width, guint height)
601 {
602         g_signal_emit_by_name(terminal, "char-size-changed",
603                               width, height);
604 }
605
606 /* Emit a "resize-window" signal.  (Pixels.) */
607 static void
608 vte_terminal_emit_resize_window(VteTerminal *terminal,
609                                 guint width, guint height)
610 {
611         g_signal_emit_by_name(terminal, "resize-window", width, height);
612 }
613
614 /* Emit a "move-window" signal.  (Pixels.) */
615 static void
616 vte_terminal_emit_move_window(VteTerminal *terminal, guint x, guint y)
617 {
618         g_signal_emit_by_name(terminal, "move-window", x, y);
619 }
620
621 /* Deselect anything which is selected and refresh the screen if needed. */
622 static void
623 vte_terminal_deselect_all(VteTerminal *terminal)
624 {
625         g_return_if_fail(VTE_IS_TERMINAL(terminal));
626         if (terminal->pvt->has_selection) {
627                 terminal->pvt->has_selection = FALSE;
628                 vte_terminal_emit_selection_changed (terminal);
629                 vte_invalidate_all(terminal);
630         }
631 }
632
633 /* Reset the set of tab stops to the default. */
634 static void
635 vte_terminal_set_tabstop(VteTerminal *terminal, int column)
636 {
637         g_return_if_fail(VTE_IS_TERMINAL(terminal));
638         if (terminal->pvt->tabstops != NULL) {
639                 /* Just set a non-NULL pointer for this column number. */
640                 g_hash_table_insert(terminal->pvt->tabstops,
641                                     GINT_TO_POINTER(2 * column + 1),
642                                     terminal);
643         }
644 }
645
646 /* Remove a tabstop. */
647 static void
648 vte_terminal_clear_tabstop(VteTerminal *terminal, int column)
649 {
650         g_return_if_fail(VTE_IS_TERMINAL(terminal));
651         if (terminal->pvt->tabstops != NULL) {
652                 /* Remove a tab stop from the hash table. */
653                 g_hash_table_remove(terminal->pvt->tabstops,
654                                     GINT_TO_POINTER(2 * column + 1));
655         }
656 }
657
658 /* Check if we have a tabstop at a given position. */
659 static gboolean
660 vte_terminal_get_tabstop(VteTerminal *terminal, int column)
661 {
662         gpointer hash;
663         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
664         if (terminal->pvt->tabstops != NULL) {
665                 hash = g_hash_table_lookup(terminal->pvt->tabstops,
666                                            GINT_TO_POINTER(2 * column + 1));
667                 return (hash != NULL);
668         } else {
669                 return FALSE;
670         }
671 }
672
673 /* Reset the set of tab stops to the default. */
674 static void
675 vte_terminal_set_default_tabstops(VteTerminal *terminal)
676 {
677         int i;
678         g_return_if_fail(VTE_IS_TERMINAL(terminal));
679         if (terminal->pvt->tabstops != NULL) {
680                 g_hash_table_destroy(terminal->pvt->tabstops);
681         }
682         terminal->pvt->tabstops = g_hash_table_new(g_direct_hash,
683                                                    g_direct_equal);
684         for (i = 0; i <= VTE_TAB_MAX; i += VTE_TAB_WIDTH) {
685                 vte_terminal_set_tabstop(terminal, i);
686         }
687 }
688
689 /* Clear the cache of the screen contents we keep. */
690 static void
691 vte_terminal_match_contents_clear(VteTerminal *terminal)
692 {
693         g_return_if_fail(VTE_IS_TERMINAL(terminal));
694         if (terminal->pvt->match_contents != NULL) {
695                 g_free(terminal->pvt->match_contents);
696                 terminal->pvt->match_contents = NULL;;
697         }
698         while (terminal->pvt->match_attributes != NULL) {
699                 g_array_free(terminal->pvt->match_attributes, FALSE);
700                 terminal->pvt->match_attributes = NULL;
701         }
702         vte_terminal_match_hilite_clear(terminal);
703 }
704
705 /* Refresh the cache of the screen contents we keep. */
706 static gboolean
707 always_selected(VteTerminal *terminal, long row, long column)
708 {
709         return TRUE;
710 }
711 static void
712 vte_terminal_match_contents_refresh(VteTerminal *terminal)
713 {
714         GArray *array;
715         g_return_if_fail(VTE_IS_TERMINAL(terminal));
716         vte_terminal_match_contents_clear(terminal);
717         array = g_array_new(FALSE, TRUE, sizeof(struct vte_char_attributes));
718         terminal->pvt->match_contents = vte_terminal_get_text(terminal,
719                                                               always_selected,
720                                                               array);
721         terminal->pvt->match_attributes = array;
722 }
723
724 /* Display string matching:  clear all matching expressions. */
725 void
726 vte_terminal_match_clear_all(VteTerminal *terminal)
727 {
728         struct vte_match_regex *regex;
729         g_return_if_fail(VTE_IS_TERMINAL(terminal));
730         while (terminal->pvt->match_regexes->len > 0) {
731                 regex = &g_array_index(terminal->pvt->match_regexes,
732                                        struct vte_match_regex,
733                                        terminal->pvt->match_regexes->len - 1);
734                 regfree(&regex->reg);
735                 memset(&regex->reg, 0, sizeof(regex->reg));
736                 regex->tag = 0;
737                 g_array_remove_index(terminal->pvt->match_regexes,
738                                      terminal->pvt->match_regexes->len - 1);
739         }
740         vte_terminal_match_hilite_clear(terminal);
741 }
742
743 /* Add a matching expression, returning the tag the widget assigns to that
744  * expression. */
745 int
746 vte_terminal_match_add(VteTerminal *terminal, const char *match)
747 {
748         struct vte_match_regex regex;
749         int ret;
750         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
751         memset(&regex, 0, sizeof(regex));
752         ret = regcomp(&regex.reg, match, REG_EXTENDED);
753         if (ret != 0) {
754                 g_warning("Error compiling regular expression \"%s\".", match);
755                 return -1;
756         }
757         regex.tag = terminal->pvt->match_regexes->len;
758         g_array_append_val(terminal->pvt->match_regexes, regex);
759         return regex.tag;
760 }
761
762 /* Check if a given cell on the screen contains part of a matched string.  If
763  * it does, return the string, and store the match tag in the optional tag
764  * argument. */
765 static char *
766 vte_terminal_match_check_int(VteTerminal *terminal, long column,
767                              long row, int *tag, int *start, int *end)
768 {
769         int i, j, ret, offset;
770         struct vte_match_regex *regex = NULL;
771         struct vte_char_attributes *attr = NULL;
772         size_t coffset;
773         regmatch_t matches[256];
774         if (tag != NULL) {
775                 *tag = -1;
776         }
777         if (start != NULL) {
778                 *start = 0;
779         }
780         if (end != NULL) {
781                 *end = 0;
782         }
783         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
784         if (terminal->pvt->match_contents == NULL) {
785                 vte_terminal_match_contents_refresh(terminal);
786         }
787         /* Map the pointer position to a portion of the string. */
788         for (offset = terminal->pvt->match_attributes->len - 1;
789              offset >= 0;
790              offset--) {
791                 attr = &g_array_index(terminal->pvt->match_attributes,
792                                       struct vte_char_attributes,
793                                       offset);
794                 if (attr != NULL) {
795                         if ((row == attr->row) && (column == attr->column)) {
796                                 break;
797                         }
798                 }
799         }
800 #ifdef VTE_DEBUG
801         if (vte_debug_on(VTE_DEBUG_EVENTS)) {
802                 if (offset < 0) {
803                         fprintf(stderr, "Cursor is not on a character.\n");
804                 } else {
805                         fprintf(stderr, "Cursor is on character %d.\n", offset);
806                 }
807         }
808 #endif
809         /* If the pointer isn't on a matchable character, bug out. */
810         if (offset < 0) {
811                 return NULL;
812         }
813         /* If the pointer is on a newline, bug out. */
814         if (g_ascii_isspace(terminal->pvt->match_contents[offset])) {
815                 return NULL;
816         }
817
818         /* Now iterate over each regex we need to match against. */
819         for (i = 0; i < terminal->pvt->match_regexes->len; i++) {
820                 regex = &g_array_index(terminal->pvt->match_regexes,
821                                        struct vte_match_regex,
822                                        i);
823                 if (regex != NULL) {
824                         /* We'll only match the first item in the buffer which
825                          * matches, so we'll have to skip each match until we
826                          * stop getting matches. */
827                         coffset = 0;
828                         ret = regexec(&regex->reg,
829                                       terminal->pvt->match_contents + coffset,
830                                       G_N_ELEMENTS(matches),
831                                       matches,
832                                       0);
833                         while (ret == 0) {
834                                 for (j = 0;
835                                      j < G_N_ELEMENTS(matches) &&
836                                      (matches[j].rm_so != -1);
837                                      j++) {
838                                         /* The offsets should be "sane". */
839                                         g_assert(matches[j].rm_so + coffset < terminal->pvt->match_attributes->len);
840                                         g_assert(matches[j].rm_eo + coffset < terminal->pvt->match_attributes->len);
841 #ifdef VTE_DEBUG
842                                         if (vte_debug_on(VTE_DEBUG_MISC)) {
843                                                 char *match;
844                                                 struct vte_char_attributes *sattr, *eattr;
845                                                 match = g_strndup(terminal->pvt->match_contents + matches[j].rm_so + coffset,
846                                                                   matches[j].rm_eo - matches[j].rm_so);
847                                                 sattr = &g_array_index(terminal->pvt->match_attributes,
848                                                                        struct vte_char_attributes,
849                                                                        matches[j].rm_so + coffset);
850                                                 eattr = &g_array_index(terminal->pvt->match_attributes,
851                                                                        struct vte_char_attributes,
852                                                                        matches[j].rm_eo + coffset - 1);
853                                                 fprintf(stderr, "Match %d `%s' from %d(%ld,%ld) to %d(%ld,%ld) (%d).\n",
854                                                         j, match,
855                                                         matches[j].rm_so + coffset,
856                                                         sattr->column,
857                                                         sattr->row,
858                                                         matches[j].rm_eo + coffset - 1,
859                                                         eattr->column,
860                                                         eattr->row,
861                                                         offset);
862                                                 g_free(match);
863
864                                         }
865 #endif
866                                         /* If the pointer is in this substring,
867                                          * then we're done. */
868                                         if ((offset >= matches[j].rm_so + coffset) &&
869                                             (offset < matches[j].rm_eo + coffset)) {
870                                                 if (tag != NULL) {
871                                                         *tag = regex->tag;
872                                                 }
873                                                 if (start != NULL) {
874                                                         *start = matches[j].rm_so + coffset;
875                                                 }
876                                                 if (end != NULL) {
877                                                         *end = matches[j].rm_eo + coffset - 1;
878                                                 }
879                                                 return g_strndup(terminal->pvt->match_contents + matches[j].rm_so + coffset,
880                                                                  matches[j].rm_eo - matches[j].rm_so);
881                                         }
882                                 }
883                                 /* Skip past the beginning of this match to
884                                  * look for more. */
885                                 coffset += (matches[0].rm_so + 1);
886                                 ret = regexec(&regex->reg,
887                                               terminal->pvt->match_contents + coffset,
888                                               G_N_ELEMENTS(matches),
889                                               matches,
890                                               0);
891                         }
892                 }
893         }
894         return NULL;
895 }
896
897 char *
898 vte_terminal_match_check(VteTerminal *terminal, long column, long row, int *tag)
899 {
900         return vte_terminal_match_check_int(terminal, column, row, tag,
901                                             NULL, NULL);
902 }
903
904 /* Update the adjustment field of the widget.  This function should be called
905  * whenever we add rows to the history or switch screens. */
906 static void
907 vte_terminal_adjust_adjustments(VteTerminal *terminal)
908 {
909         gboolean changed;
910         long delta, next;
911         long page_size;
912         long rows;
913
914         g_return_if_fail(VTE_IS_TERMINAL(terminal));
915         g_return_if_fail(terminal->pvt->screen != NULL);
916         g_return_if_fail(terminal->pvt->screen->row_data != NULL);
917
918         /* Adjust the vertical, uh, adjustment. */
919         changed = FALSE;
920
921         /* The lower value should be the first row in the buffer. */
922         delta = vte_ring_delta(terminal->pvt->screen->row_data);
923 #ifdef VTE_DEBUG
924         if (vte_debug_on(VTE_DEBUG_IO)) {
925                 fprintf(stderr, "Changing adjustment values "
926                         "(delta = %ld, scroll = %ld).\n",
927                         delta, terminal->pvt->screen->scroll_delta);
928         }
929 #endif
930         if (terminal->adjustment->lower != delta) {
931                 terminal->adjustment->lower = delta;
932                 changed = TRUE;
933         }
934
935         /* The upper value is the number of rows which might be visible.  (Add
936          * one to the cursor offset because it's zero-based.) */
937         next = vte_ring_delta(terminal->pvt->screen->row_data) +
938                vte_ring_length(terminal->pvt->screen->row_data);
939         rows = MAX(next,
940                    terminal->pvt->screen->cursor_current.row + 1);
941         if (terminal->adjustment->upper != rows) {
942                 terminal->adjustment->upper = rows;
943                 changed = TRUE;
944         }
945
946         /* The step increment should always be one. */
947         if (terminal->adjustment->step_increment != 1) {
948                 terminal->adjustment->step_increment = 1;
949                 changed = TRUE;
950         }
951
952         /* Set the number of rows the user sees to the number of rows the
953          * user sees. */
954         page_size = terminal->row_count;
955         if (terminal->adjustment->page_size != page_size) {
956                 terminal->adjustment->page_size = page_size;
957                 changed = TRUE;
958         }
959
960         /* Clicking in the empty area should scroll one screen, so set the
961          * page size to the number of visible rows. */
962         if (terminal->adjustment->page_increment != page_size) {
963                 terminal->adjustment->page_increment = page_size;
964                 changed = TRUE;
965         }
966
967         /* Set the scrollbar adjustment to where the screen wants it to be. */
968         if (floor(gtk_adjustment_get_value(terminal->adjustment)) !=
969             terminal->pvt->screen->scroll_delta) {
970                 gtk_adjustment_set_value(terminal->adjustment,
971                                          terminal->pvt->screen->scroll_delta);
972                 changed = TRUE;
973         }
974
975         /* If anything changed, signal that there was a change. */
976         if (changed == TRUE) {
977 #ifdef VTE_DEBUG
978                 if (vte_debug_on(VTE_DEBUG_IO)) {
979                         fprintf(stderr, "Changed adjustment values "
980                                 "(delta = %ld, scroll = %ld).\n",
981                                 delta, terminal->pvt->screen->scroll_delta);
982                 }
983 #endif
984                 vte_terminal_match_contents_clear(terminal);
985                 vte_terminal_emit_contents_changed(terminal);
986                 gtk_adjustment_changed(terminal->adjustment);
987         }
988 }
989
990 /* Scroll up or down in the current screen. */
991 static void
992 vte_terminal_scroll_pages(VteTerminal *terminal, gint pages)
993 {
994         glong destination;
995         g_return_if_fail(VTE_IS_TERMINAL(terminal));
996 #ifdef VTE_DEBUG
997         if (vte_debug_on(VTE_DEBUG_IO)) {
998                 fprintf(stderr, "Scrolling %d pages.\n", pages);
999         }
1000 #endif
1001         /* Calculate the ideal position where we want to be before clamping. */
1002         destination = floor(gtk_adjustment_get_value(terminal->adjustment));
1003         destination += (pages * terminal->row_count);
1004         /* Can't scroll past data we have. */
1005         destination = MIN(destination,
1006                           terminal->adjustment->upper - terminal->row_count);
1007         /* Can't scroll up past zero. */
1008         destination = MAX(terminal->adjustment->lower, destination);
1009         /* Tell the scrollbar to adjust itself. */
1010         gtk_adjustment_set_value(terminal->adjustment, destination);
1011         gtk_adjustment_changed(terminal->adjustment);
1012 }
1013
1014 /* Scroll so that the scroll delta is the insertion delta. */
1015 static void
1016 vte_terminal_scroll_to_bottom(VteTerminal *terminal)
1017 {
1018         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1019         if (floor(gtk_adjustment_get_value(terminal->adjustment)) !=
1020             terminal->pvt->screen->insert_delta) {
1021                 gtk_adjustment_set_value(terminal->adjustment,
1022                                          terminal->pvt->screen->insert_delta);
1023                 gtk_adjustment_changed(terminal->adjustment);
1024         }
1025 }
1026
1027 /* Call another function, offsetting any long arguments by the given
1028  * increment value. */
1029 static void
1030 vte_sequence_handler_offset(VteTerminal *terminal,
1031                             const char *match,
1032                             GQuark match_quark,
1033                             GValueArray *params,
1034                             int increment,
1035                             VteTerminalSequenceHandler handler)
1036 {
1037         int i;
1038         long val;
1039         GValue *value;
1040         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1041         /* Decrement the parameters and let the _cs handler deal with it. */
1042         for (i = 0; (params != NULL) && (i < params->n_values); i++) {
1043                 value = g_value_array_get_nth(params, i);
1044                 if (G_VALUE_HOLDS_LONG(value)) {
1045                         val = g_value_get_long(value);
1046                         val += increment;
1047                         g_value_set_long(value, val);
1048                 }
1049         }
1050         handler(terminal, match, match_quark, params);
1051 }
1052
1053 /* Call another function a given number of times, or once. */
1054 static void
1055 vte_sequence_handler_multiple(VteTerminal *terminal,
1056                               const char *match,
1057                               GQuark match_quark,
1058                               GValueArray *params,
1059                               VteTerminalSequenceHandler handler)
1060 {
1061         long val = 1;
1062         int i;
1063         GValue *value;
1064         if ((params != NULL) && (params->n_values > 0)) {
1065                 value = g_value_array_get_nth(params, 0);
1066                 if (G_VALUE_HOLDS_LONG(value)) {
1067                         val = g_value_get_long(value);
1068                 }
1069         }
1070         for (i = 0; i < val; i++) {
1071                 handler(terminal, match, match_quark, NULL);
1072         }
1073 }
1074
1075 /* Insert a blank line at an arbitrary position. */
1076 static void
1077 vte_insert_line_int(VteTerminal *terminal, long position)
1078 {
1079         GArray *array;
1080         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1081         /* Pad out the line data to the insertion point. */
1082         while (vte_ring_next(terminal->pvt->screen->row_data) < position) {
1083                 array = vte_new_row_data();
1084                 vte_ring_append(terminal->pvt->screen->row_data, array);
1085         }
1086         /* If we haven't inserted a line yet, insert a new one. */
1087         array = vte_new_row_data();
1088         if (vte_ring_next(terminal->pvt->screen->row_data) >= position) {
1089                 vte_ring_insert(terminal->pvt->screen->row_data, position, array);
1090         } else {
1091                 vte_ring_append(terminal->pvt->screen->row_data, array);
1092         }
1093 }
1094
1095 /* Remove a line at an arbitrary position. */
1096 static void
1097 vte_remove_line_int(VteTerminal *terminal, long position)
1098 {
1099         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1100         if (vte_ring_next(terminal->pvt->screen->row_data) > position) {
1101                 vte_ring_remove(terminal->pvt->screen->row_data, position, TRUE);
1102         }
1103 }
1104
1105 /* Change the encoding used for the terminal to the given codeset, or the
1106  * locale default if NULL is passed in. */
1107 static void
1108 vte_terminal_set_encoding(VteTerminal *terminal, const char *codeset)
1109 {
1110         const char *old_codeset;
1111         GQuark encoding_quark;
1112         iconv_t conv;
1113         char *ibuf, *obuf, *obufptr;
1114         size_t icount, ocount;
1115
1116         old_codeset = terminal->pvt->encoding;
1117
1118         if (codeset == NULL) {
1119                 codeset = nl_langinfo(CODESET);
1120         }
1121
1122         /* Set up the conversion for incoming-to-wchars. */
1123         if (terminal->pvt->incoming_conv != NULL) {
1124                 iconv_close(terminal->pvt->incoming_conv);
1125         }
1126         terminal->pvt->incoming_conv = iconv_open("WCHAR_T", codeset);
1127
1128         /* Set up the conversions for wchar/utf-8 to outgoing. */
1129         if (terminal->pvt->outgoing_conv_wide != NULL) {
1130                 iconv_close(terminal->pvt->outgoing_conv_wide);
1131         }
1132         terminal->pvt->outgoing_conv_wide = iconv_open(codeset, "WCHAR_T");
1133
1134         if (terminal->pvt->outgoing_conv_utf8 != NULL) {
1135                 iconv_close(terminal->pvt->outgoing_conv_utf8);
1136         }
1137         terminal->pvt->outgoing_conv_utf8 = iconv_open(codeset, "UTF-8");
1138
1139         /* Set the terminal's encoding to the new value. */
1140         encoding_quark = g_quark_from_string(codeset);
1141         terminal->pvt->encoding = g_quark_to_string(encoding_quark);
1142
1143         /* Convert any buffered output bytes. */
1144         if (terminal->pvt->n_outgoing > 0) {
1145                 icount = terminal->pvt->n_outgoing;
1146                 ibuf = terminal->pvt->outgoing;
1147                 ocount = icount * VTE_UTF8_BPC + 1;
1148                 obuf = obufptr = g_malloc(ocount);
1149                 conv = iconv_open(codeset, old_codeset);
1150                 if (conv != NULL) {
1151                         if (iconv(conv, &ibuf, &icount, &obuf, &ocount) == -1) {
1152                                 /* Darn, it failed.  Leave it alone. */
1153                                 g_free(obufptr);
1154 #ifdef VTE_DEBUG
1155                                 if (vte_debug_on(VTE_DEBUG_IO)) {
1156                                         fprintf(stderr, "Error converting %ld "
1157                                                 "pending output bytes (%s) "
1158                                                 "skipping.\n",
1159                                                 (long) terminal->pvt->n_outgoing,
1160                                                 strerror(errno));
1161                                 }
1162 #endif
1163                         } else {
1164                                 g_free(terminal->pvt->outgoing);
1165                                 terminal->pvt->outgoing = obufptr;
1166                                 terminal->pvt->n_outgoing = obuf - obufptr;
1167 #ifdef VTE_DEBUG
1168                                 if (vte_debug_on(VTE_DEBUG_IO)) {
1169                                         fprintf(stderr, "Converted %ld pending "
1170                                                 "output bytes.\n",
1171                                                 (long) terminal->pvt->n_outgoing);
1172                                 }
1173 #endif
1174                         }
1175                         iconv_close(conv);
1176                 }
1177         }
1178
1179 #ifdef VTE_DEBUG
1180         if (vte_debug_on(VTE_DEBUG_IO)) {
1181                 fprintf(stderr, "Set terminal encoding to `%s'.\n",
1182                         terminal->pvt->encoding);
1183         }
1184 #endif
1185 }
1186
1187 /* End alternate character set. */
1188 static void
1189 vte_sequence_handler_ae(VteTerminal *terminal,
1190                         const char *match,
1191                         GQuark match_quark,
1192                         GValueArray *params)
1193 {
1194         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1195         terminal->pvt->screen->defaults.alternate = 0;
1196 }
1197
1198 /* Add a line at the current cursor position. */
1199 static void
1200 vte_sequence_handler_al(VteTerminal *terminal,
1201                         const char *match,
1202                         GQuark match_quark,
1203                         GValueArray *params)
1204 {
1205         VteScreen *screen;
1206         GtkWidget *widget;
1207         long start, end;
1208         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1209         widget = GTK_WIDGET(terminal);
1210         screen = terminal->pvt->screen;
1211         if (screen->scrolling_restricted) {
1212                 start = screen->insert_delta + screen->scrolling_region.start;
1213                 end = screen->insert_delta + screen->scrolling_region.end;
1214         } else {
1215                 start = screen->insert_delta;
1216                 end = screen->insert_delta + terminal->row_count - 1;
1217         }
1218         vte_remove_line_int(terminal, end);
1219         vte_insert_line_int(terminal, screen->cursor_current.row);
1220         screen->cursor_current.row++;
1221         if (start - screen->insert_delta < terminal->row_count / 2) {
1222 #if 0
1223                 gdk_window_scroll(widget->window,
1224                                   0,
1225                                   terminal->char_height);
1226                 vte_invalidate_cells(terminal,
1227                                      0, terminal->column_count,
1228                                      0, start + 2);
1229                 vte_invalidate_cells(terminal,
1230                                      0, terminal->column_count,
1231                                      end, terminal->row_count);
1232 #else
1233                 vte_invalidate_cells(terminal,
1234                                      0, terminal->column_count,
1235                                      start, end - start + 1);
1236 #endif
1237         } else {
1238                 vte_invalidate_cells(terminal,
1239                                      0, terminal->column_count,
1240                                      start, end - start + 1);
1241         }
1242 }
1243
1244 /* Add N lines at the current cursor position. */
1245 static void
1246 vte_sequence_handler_AL(VteTerminal *terminal,
1247                         const char *match,
1248                         GQuark match_quark,
1249                         GValueArray *params)
1250 {
1251         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1252         vte_sequence_handler_multiple(terminal, match, match_quark, params,
1253                                       vte_sequence_handler_al);
1254 }
1255
1256 /* Start using alternate character set. */
1257 static void
1258 vte_sequence_handler_as(VteTerminal *terminal,
1259                         const char *match,
1260                         GQuark match_quark,
1261                         GValueArray *params)
1262 {
1263         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1264         terminal->pvt->screen->defaults.alternate = 1;
1265 }
1266
1267 /* Beep. */
1268 static void
1269 vte_sequence_handler_bl(VteTerminal *terminal,
1270                         const char *match,
1271                         GQuark match_quark,
1272                         GValueArray *params)
1273 {
1274         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1275         if (terminal->pvt->audible_bell) {
1276                 /* Feep. */
1277                 gdk_beep();
1278         } else {
1279                 /* Visual bell. */
1280                 vte_sequence_handler_vb(terminal, match, match_quark, params);
1281         }
1282 }
1283
1284 /* Backtab. */
1285 static void
1286 vte_sequence_handler_bt(VteTerminal *terminal,
1287                         const char *match,
1288                         GQuark match_quark,
1289                         GValueArray *params)
1290 {
1291         long newcol;
1292         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1293
1294         /* Calculate which column is the previous tab stop. */
1295         newcol = terminal->pvt->screen->cursor_current.col;
1296
1297         if (terminal->pvt->tabstops != NULL) {
1298                 /* Find the next tabstop. */
1299                 for (newcol += (terminal->column_count - 1);
1300                      newcol >= 0;
1301                      newcol--) {
1302                         if (vte_terminal_get_tabstop(terminal,
1303                                                      newcol % terminal->column_count)) {
1304                                 break;
1305                         }
1306                 }
1307         }
1308
1309         /* If we have no tab stops, stop right here. */
1310         if (newcol <= 0) {
1311                 return;
1312         }
1313
1314         /* Warp the cursor. */
1315 #ifdef VTE_DEBUG
1316         if (vte_debug_on(VTE_DEBUG_PARSE)) {
1317                 fprintf(stderr, "Moving cursor to column %ld.\n", (long)newcol);
1318         }
1319 #endif
1320         terminal->pvt->screen->cursor_current.col = newcol;
1321 }
1322
1323 /* Clear from the cursor position to the beginning of the line. */
1324 static void
1325 vte_sequence_handler_cb(VteTerminal *terminal,
1326                         const char *match,
1327                         GQuark match_quark,
1328                         GValueArray *params)
1329 {
1330         GArray *rowdata;
1331         long i;
1332         VteScreen *screen;
1333         struct vte_charcell *pcell;
1334         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1335         screen = terminal->pvt->screen;
1336         /* If the cursor is actually on the screen, clear data in the row
1337          * which corresponds to the cursor. */
1338         if (vte_ring_next(screen->row_data) > screen->cursor_current.row) {
1339                 struct vte_charcell defaults;
1340                 /* Get the data for the row which the cursor points to. */
1341                 rowdata = vte_ring_index(screen->row_data,
1342                                          GArray*,
1343                                          screen->cursor_current.row);
1344                 /* Clear the data up to the current column with the default
1345                  * attributes. */
1346                 memset(&defaults, 0, sizeof(defaults));
1347                 defaults.fore = screen->defaults.fore;
1348                 defaults.back = screen->defaults.back;
1349                 defaults.c = 0;
1350                 defaults.columns = 1;
1351                 for (i = 0;
1352                      (i < screen->cursor_current.col) && (i < rowdata->len);
1353                      i++) {
1354                         pcell = &g_array_index(rowdata, struct vte_charcell, i);
1355                         if (pcell != NULL) {
1356                                 *pcell = defaults;
1357                         }
1358                 }
1359                 /* Repaint this row. */
1360                 vte_invalidate_cells(terminal,
1361                                      0, terminal->column_count,
1362                                      screen->cursor_current.row, 1);
1363         }
1364 }
1365
1366 /* Clear below the current line. */
1367 static void
1368 vte_sequence_handler_cd(VteTerminal *terminal,
1369                         const char *match,
1370                         GQuark match_quark,
1371                         GValueArray *params)
1372 {
1373         GArray *rowdata;
1374         long i;
1375         VteScreen *screen;
1376         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1377         screen = terminal->pvt->screen;
1378         /* If the cursor is actually on the screen, clear data in the row
1379          * the cursor is in and all rows below the cursor. */
1380         for (i = screen->cursor_current.row;
1381              i < vte_ring_next(screen->row_data);
1382              i++) {
1383                 /* Get the data for the row we're removing. */
1384                 rowdata = vte_ring_index(screen->row_data, GArray*, i);
1385                 /* Remove it. */
1386                 while ((rowdata != NULL) && (rowdata->len > 0)) {
1387                         g_array_remove_index(rowdata, rowdata->len - 1);
1388                 }
1389                 /* Repaint this row. */
1390                 vte_invalidate_cells(terminal,
1391                                      0, terminal->column_count,
1392                                      i, 1);
1393         }
1394 }
1395
1396 /* Clear from the cursor position to the end of the line. */
1397 static void
1398 vte_sequence_handler_ce(VteTerminal *terminal,
1399                         const char *match,
1400                         GQuark match_quark,
1401                         GValueArray *params)
1402 {
1403         GArray *rowdata;
1404         VteScreen *screen;
1405         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1406         screen = terminal->pvt->screen;
1407         /* Get the data for the row which the cursor points to. */
1408         vte_terminal_ensure_cursor(terminal);
1409         rowdata = vte_ring_index(screen->row_data, GArray*,
1410                                  screen->cursor_current.row);
1411         /* Remove the data at the end of the array. */
1412         while (rowdata->len > screen->cursor_current.col) {
1413                 g_array_remove_index(rowdata, rowdata->len - 1);
1414         }
1415         /* Now insert empty cells with the default attributes. */
1416         while (rowdata->len < terminal->column_count) {
1417                 g_array_append_val(rowdata, screen->defaults);
1418         }
1419         /* Repaint this row. */
1420         vte_invalidate_cells(terminal,
1421                              0, terminal->column_count,
1422                              screen->cursor_current.row, 1);
1423 }
1424
1425 /* Move the cursor to the given column (horizontal position). */
1426 static void
1427 vte_sequence_handler_ch(VteTerminal *terminal,
1428                         const char *match,
1429                         GQuark match_quark,
1430                         GValueArray *params)
1431 {
1432         VteScreen *screen;
1433         GValue *value;
1434         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1435         screen = terminal->pvt->screen;
1436         /* We only care if there's a parameter in there. */
1437         if ((params != NULL) && (params->n_values > 0)) {
1438                 value = g_value_array_get_nth(params, 0);
1439                 if (G_VALUE_HOLDS_LONG(value)) {
1440                         /* Move the cursor. */
1441                         screen->cursor_current.col = g_value_get_long(value);
1442                 }
1443         }
1444 }
1445
1446 /* Clear the screen and home the cursor. */
1447 static void
1448 vte_sequence_handler_cl(VteTerminal *terminal,
1449                         const char *match,
1450                         GQuark match_quark,
1451                         GValueArray *params)
1452 {
1453         vte_sequence_handler_clear_screen(terminal, NULL, 0, NULL);
1454         vte_sequence_handler_ho(terminal, NULL, 0, NULL);
1455 }
1456
1457 /* Move the cursor to the given position. */
1458 static void
1459 vte_sequence_handler_cm(VteTerminal *terminal,
1460                         const char *match,
1461                         GQuark match_quark,
1462                         GValueArray *params)
1463 {
1464         GValue *row, *col;
1465         long rowval, colval;
1466         VteScreen *screen;
1467         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1468         screen = terminal->pvt->screen;
1469         /* We need at least two parameters. */
1470         if ((params != NULL) && (params->n_values >= 2)) {
1471                 /* The first is the row, the second is the column. */
1472                 row = g_value_array_get_nth(params, 0);
1473                 col = g_value_array_get_nth(params, 1);
1474                 if (G_VALUE_HOLDS_LONG(row) &&
1475                     G_VALUE_HOLDS_LONG(col)) {
1476                         rowval = g_value_get_long(row);
1477                         colval = g_value_get_long(col);
1478                         rowval = MAX(0, rowval);
1479                         rowval = MIN(rowval, terminal->row_count - 1);
1480                         colval = MAX(0, colval);
1481                         colval = MIN(colval, terminal->column_count - 1);
1482                         screen->cursor_current.row = rowval +
1483                                                      screen->insert_delta;
1484                         screen->cursor_current.col = colval;
1485                 }
1486         }
1487 }
1488
1489 /* Clear from the current line. */
1490 static void
1491 vte_sequence_handler_clear_current_line(VteTerminal *terminal,
1492                                         const char *match,
1493                                         GQuark match_quark,
1494                                         GValueArray *params)
1495 {
1496         GArray *rowdata;
1497         VteScreen *screen;
1498         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1499         screen = terminal->pvt->screen;
1500         /* If the cursor is actually on the screen, clear data in the row
1501          * which corresponds to the cursor. */
1502         if (vte_ring_next(screen->row_data) > screen->cursor_current.row) {
1503                 /* Get the data for the row which the cursor points to. */
1504                 rowdata = vte_ring_index(screen->row_data, GArray*,
1505                                          screen->cursor_current.row);
1506                 /* Remove it. */
1507                 while (rowdata->len > 0) {
1508                         g_array_remove_index(rowdata, rowdata->len - 1);
1509                 }
1510                 /* Repaint this row. */
1511                 vte_invalidate_cells(terminal,
1512                                      0, terminal->column_count,
1513                                      screen->cursor_current.row, 1);
1514         }
1515 }
1516
1517 /* Carriage return. */
1518 static void
1519 vte_sequence_handler_cr(VteTerminal *terminal,
1520                         const char *match,
1521                         GQuark match_quark,
1522                         GValueArray *params)
1523 {
1524         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1525         terminal->pvt->screen->cursor_current.col = 0;
1526 }
1527
1528 /* Restrict scrolling and updates to a subset of the visible lines. */
1529 static void
1530 vte_sequence_handler_cs(VteTerminal *terminal,
1531                         const char *match,
1532                         GQuark match_quark,
1533                         GValueArray *params)
1534 {
1535         long start, end, rows;
1536         GValue *value;
1537         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1538         /* We require two parameters. */
1539         if ((params == NULL) || (params->n_values < 2)) {
1540                 terminal->pvt->screen->scrolling_restricted = FALSE;
1541                 return;
1542         }
1543         /* Extract the two values. */
1544         value = g_value_array_get_nth(params, 0);
1545         start = g_value_get_long(value);
1546         value = g_value_array_get_nth(params, 1);
1547         end = g_value_get_long(value);
1548         /* Set the right values. */
1549         terminal->pvt->screen->scrolling_region.start = start;
1550         terminal->pvt->screen->scrolling_region.end = end;
1551         terminal->pvt->screen->scrolling_restricted = TRUE;
1552         /* Special case -- run wild, run free. */
1553         rows = terminal->row_count;
1554         if ((terminal->pvt->screen->scrolling_region.start == 0) &&
1555             (terminal->pvt->screen->scrolling_region.end == rows - 1)) {
1556                 terminal->pvt->screen->scrolling_restricted = FALSE;
1557         }
1558 }
1559
1560 /* Restrict scrolling and updates to a subset of the visible lines, because
1561  * GNU Emacs is special. */
1562 static void
1563 vte_sequence_handler_cS(VteTerminal *terminal,
1564                         const char *match,
1565                         GQuark match_quark,
1566                         GValueArray *params)
1567 {
1568         long start, end, rows;
1569         GValue *value;
1570         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1571         /* We require four parameters. */
1572         if ((params == NULL) || (params->n_values < 2)) {
1573                 terminal->pvt->screen->scrolling_restricted = FALSE;
1574                 return;
1575         }
1576         /* Extract the two parameters we care about, encoded as the number
1577          * of lines above and below the scrolling region, respectively. */
1578         value = g_value_array_get_nth(params, 1);
1579         start = g_value_get_long(value);
1580         value = g_value_array_get_nth(params, 2);
1581         end = (terminal->row_count - 1) - g_value_get_long(value);
1582         /* Set the right values. */
1583         terminal->pvt->screen->scrolling_region.start = start;
1584         terminal->pvt->screen->scrolling_region.end = end;
1585         terminal->pvt->screen->scrolling_restricted = TRUE;
1586         /* Special case -- run wild, run free. */
1587         rows = terminal->row_count;
1588         if ((terminal->pvt->screen->scrolling_region.start == 0) &&
1589             (terminal->pvt->screen->scrolling_region.end == rows - 1)) {
1590                 terminal->pvt->screen->scrolling_restricted = FALSE;
1591         }
1592 }
1593
1594 /* Clear all tab stops. */
1595 static void
1596 vte_sequence_handler_ct(VteTerminal *terminal,
1597                         const char *match,
1598                         GQuark match_quark,
1599                         GValueArray *params)
1600 {
1601         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1602         if (terminal->pvt->tabstops != NULL) {
1603                 g_hash_table_destroy(terminal->pvt->tabstops);
1604                 terminal->pvt->tabstops = NULL;
1605         }
1606 }
1607
1608 /* Move the cursor to the given row (vertical position). */
1609 static void
1610 vte_sequence_handler_cv(VteTerminal *terminal,
1611                         const char *match,
1612                         GQuark match_quark,
1613                         GValueArray *params)
1614 {
1615         VteScreen *screen;
1616         GValue *value;
1617         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1618         screen = terminal->pvt->screen;
1619         /* We only care if there's a parameter in there. */
1620         if ((params != NULL) && (params->n_values > 0)) {
1621                 value = g_value_array_get_nth(params, 0);
1622                 if (G_VALUE_HOLDS_LONG(value)) {
1623                         /* Move the cursor. */
1624                         screen->cursor_current.row = g_value_get_long(value) +
1625                                                      screen->insert_delta;
1626                 }
1627         }
1628 }
1629
1630 /* Delete a character at the current cursor position. */
1631 static void
1632 vte_sequence_handler_dc(VteTerminal *terminal,
1633                         const char *match,
1634                         GQuark match_quark,
1635                         GValueArray *params)
1636 {
1637         VteScreen *screen;
1638         GArray *rowdata;
1639         long col;
1640
1641         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1642         screen = terminal->pvt->screen;
1643
1644         if (vte_ring_next(screen->row_data) > screen->cursor_current.row) {
1645                 /* Get the data for the row which the cursor points to. */
1646                 rowdata = vte_ring_index(screen->row_data,
1647                                          GArray*,
1648                                          screen->cursor_current.row);
1649                 col = screen->cursor_current.col;
1650                 /* Remove the column. */
1651                 if (col < rowdata->len) {
1652                         g_array_remove_index(rowdata, col);
1653                 }
1654                 /* Repaint this row. */
1655                 vte_invalidate_cells(terminal,
1656                                      0, terminal->column_count,
1657                                      screen->cursor_current.row, 1);
1658         }
1659 }
1660
1661 /* Delete N characters at the current cursor position. */
1662 static void
1663 vte_sequence_handler_DC(VteTerminal *terminal,
1664                         const char *match,
1665                         GQuark match_quark,
1666                         GValueArray *params)
1667 {
1668         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1669         vte_sequence_handler_multiple(terminal, match, match_quark, params,
1670                                       vte_sequence_handler_dc);
1671 }
1672
1673 /* Delete a line at the current cursor position. */
1674 static void
1675 vte_sequence_handler_dl(VteTerminal *terminal,
1676                         const char *match,
1677                         GQuark match_quark,
1678                         GValueArray *params)
1679 {
1680         VteScreen *screen;
1681         long end;
1682         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1683         screen = terminal->pvt->screen;
1684         if (screen->scrolling_restricted) {
1685                 end = screen->insert_delta + screen->scrolling_region.end;
1686         } else {
1687                 end = screen->insert_delta + terminal->row_count - 1;
1688         }
1689         vte_remove_line_int(terminal, screen->cursor_current.row);
1690         vte_insert_line_int(terminal, end);
1691         /* Repaint the entire screen. */
1692         vte_invalidate_all(terminal);
1693 }
1694
1695 /* Delete N lines at the current cursor position. */
1696 static void
1697 vte_sequence_handler_DL(VteTerminal *terminal,
1698                         const char *match,
1699                         GQuark match_quark,
1700                         GValueArray *params)
1701 {
1702         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1703         vte_sequence_handler_multiple(terminal, match, match_quark, params,
1704                                       vte_sequence_handler_dl);
1705 }
1706
1707 /* Make sure we have enough rows and columns to hold data at the current
1708  * cursor position. */
1709 static void
1710 vte_terminal_ensure_cursor(VteTerminal *terminal)
1711 {
1712         GArray *array;
1713         VteScreen *screen;
1714         struct vte_charcell cell;
1715
1716         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1717
1718         screen = terminal->pvt->screen;
1719
1720         while (screen->cursor_current.row >= vte_ring_next(screen->row_data)) {
1721                 array = vte_new_row_data();
1722                 vte_ring_append(screen->row_data, array);
1723         }
1724
1725         array = vte_ring_index(screen->row_data,
1726                                GArray*,
1727                                screen->cursor_current.row);
1728
1729         if (array != NULL) {
1730                 /* Add enough characters to fill out the row. */
1731                 memset(&cell, 0, sizeof(cell));
1732                 cell.fore = VTE_DEF_FG;
1733                 cell.back = VTE_DEF_BG;
1734                 cell.c = ' ';
1735                 cell.columns = wcwidth(cell.c);
1736                 /* Add enough cells at the end to make sure we have one for
1737                  * this column. */
1738                 while ((array->len <= screen->cursor_current.col) &&
1739                        (array->len < terminal->column_count)) {
1740                         array = g_array_append_val(array, cell);
1741                 }
1742         }
1743 }
1744
1745 static void
1746 vte_terminal_scroll_insertion(VteTerminal *terminal)
1747 {
1748         long rows, delta;
1749         VteScreen *screen;
1750
1751         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1752         screen = terminal->pvt->screen;
1753
1754         /* Make sure that the bottom row is visible, and that it's in
1755          * the buffer (even if it's empty).  This usually causes the
1756          * top row to become a history-only row. */
1757         rows = MAX(vte_ring_next(screen->row_data),
1758                    screen->cursor_current.row + 1);
1759         delta = MAX(0, rows - terminal->row_count);
1760
1761         /* Adjust the insert delta and scroll if needed. */
1762         if (delta != screen->insert_delta) {
1763                 vte_terminal_ensure_cursor(terminal);
1764                 screen->insert_delta = delta;
1765                 /* Update scroll bar adjustments. */
1766                 vte_terminal_adjust_adjustments(terminal);
1767         }
1768 }
1769
1770 /* Scroll forward. */
1771 static void
1772 vte_sequence_handler_do(VteTerminal *terminal,
1773                         const char *match,
1774                         GQuark match_quark,
1775                         GValueArray *params)
1776 {
1777         GtkWidget *widget;
1778         long col, row, start, end;
1779         VteScreen *screen;
1780
1781         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1782         widget = GTK_WIDGET(terminal);
1783         screen = terminal->pvt->screen;
1784
1785         start = screen->scrolling_region.start + screen->insert_delta;
1786         end = screen->scrolling_region.end + screen->insert_delta;
1787         col = screen->cursor_current.col;
1788         row = screen->cursor_current.row;
1789
1790         if (screen->scrolling_restricted) {
1791                 if (row == end) {
1792                         /* If we're at the end of the scrolling region, add a
1793                          * line at the bottom to scroll the top off. */
1794                         vte_remove_line_int(terminal, start);
1795                         vte_insert_line_int(terminal, end);
1796                         if ((terminal->pvt->bg_image == NULL) &&
1797                             (!terminal->pvt->bg_transparent)) {
1798 #if 0
1799                                 /* Scroll the window. */
1800                                 gdk_window_scroll(widget->window,
1801                                                   0,
1802                                                   -terminal->char_height);
1803                                 /* We need to redraw the last row of the
1804                                  * scrolling region, and anything beyond. */
1805                                 vte_invalidate_cells(terminal,
1806                                                      0, terminal->column_count,
1807                                                      end, terminal->row_count);
1808                                 /* Also redraw anything above the scrolling
1809                                  * region. */
1810                                 vte_invalidate_cells(terminal,
1811                                                      0, terminal->column_count,
1812                                                      0, start);
1813 #else
1814                                 vte_invalidate_cells(terminal,
1815                                                      0,
1816                                                      terminal->column_count,
1817                                                      start,
1818                                                      end - start + 1);
1819 #endif
1820                         } else {
1821                                 /* If we have a background image, we need to
1822                                  * redraw the entire window. */
1823                                 vte_invalidate_cells(terminal,
1824                                                      0,
1825                                                      terminal->column_count,
1826                                                      start,
1827                                                      end - start + 1);
1828                         }
1829                 } else {
1830                         /* Otherwise, just move the cursor down. */
1831                         screen->cursor_current.row++;
1832                 }
1833         } else {
1834                 /* Move the cursor down. */
1835                 screen->cursor_current.row++;
1836
1837                 /* Adjust the insert delta so that the row the cursor is on
1838                  * is viewable if the insert delta is equal to the scrolling
1839                  * delta. */
1840                 vte_terminal_scroll_insertion(terminal);
1841         }
1842 }
1843
1844 /* Cursor down. */
1845 static void
1846 vte_sequence_handler_DO(VteTerminal *terminal,
1847                         const char *match,
1848                         GQuark match_quark,
1849                         GValueArray *params)
1850 {
1851         vte_sequence_handler_multiple(terminal, match, match_quark, params,
1852                                       vte_sequence_handler_do);
1853 }
1854
1855 /* Start using alternate character set. */
1856 static void
1857 vte_sequence_handler_eA(VteTerminal *terminal,
1858                         const char *match,
1859                         GQuark match_quark,
1860                         GValueArray *params)
1861 {
1862         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1863         vte_sequence_handler_ae(terminal, match, match_quark, params);
1864 }
1865
1866 /* Erase characters starting at the cursor position (overwriting N with
1867  * spaces, but not moving the cursor). */
1868 static void
1869 vte_sequence_handler_ec(VteTerminal *terminal,
1870                         const char *match,
1871                         GQuark match_quark,
1872                         GValueArray *params)
1873 {
1874         VteScreen *screen;
1875         GArray *rowdata;
1876         GValue *value;
1877         struct vte_charcell *cell;
1878         long col, i, count;
1879
1880         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1881         screen = terminal->pvt->screen;
1882
1883         /* If we got a parameter, use it. */
1884         count = 1;
1885         if ((params != NULL) && (params->n_values > 0)) {
1886                 value = g_value_array_get_nth(params, 0);
1887                 if (G_VALUE_HOLDS_LONG(value)) {
1888                         count = g_value_get_long(value);
1889                 }
1890         }
1891
1892         /* Clear out the given number of characters. */
1893         if (vte_ring_next(screen->row_data) > screen->cursor_current.row) {
1894                 /* Get the data for the row which the cursor points to. */
1895                 rowdata = vte_ring_index(screen->row_data,
1896                                          GArray*,
1897                                          screen->cursor_current.row);
1898                 /* Write over the same characters. */
1899                 for (i = 0; i < count; i++) {
1900                         col = screen->cursor_current.col + i;
1901                         if ((col < rowdata->len) && (col >= 0)) {
1902                                 cell = &g_array_index(rowdata,
1903                                                       struct vte_charcell,
1904                                                       col);
1905                                 *cell = screen->defaults;
1906                         }
1907                 }
1908                 /* Repaint this row. */
1909                 vte_invalidate_cells(terminal,
1910                                      0, terminal->column_count,
1911                                      screen->cursor_current.row, 1);
1912         }
1913 }
1914
1915 /* End insert mode. */
1916 static void
1917 vte_sequence_handler_ei(VteTerminal *terminal,
1918                         const char *match,
1919                         GQuark match_quark,
1920                         GValueArray *params)
1921 {
1922         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1923         terminal->pvt->screen->insert_mode = FALSE;
1924 }
1925
1926 /* Move the cursor to the home position. */
1927 static void
1928 vte_sequence_handler_ho(VteTerminal *terminal,
1929                         const char *match,
1930                         GQuark match_quark,
1931                         GValueArray *params)
1932 {
1933         VteScreen *screen;
1934         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1935         screen = terminal->pvt->screen;
1936         screen->cursor_current.row = screen->insert_delta;
1937         screen->cursor_current.col = 0;
1938 }
1939
1940 /* Insert a character. */
1941 static void
1942 vte_sequence_handler_ic(VteTerminal *terminal,
1943                         const char *match,
1944                         GQuark match_quark,
1945                         GValueArray *params)
1946 {
1947         long row, col;
1948         VteScreen *screen;
1949
1950         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1951         screen = terminal->pvt->screen;
1952
1953         row = screen->cursor_current.row;
1954         col = screen->cursor_current.col;
1955
1956         vte_terminal_insert_char(GTK_WIDGET(terminal), ' ', TRUE);
1957
1958         screen->cursor_current.row = row;
1959         screen->cursor_current.col = col;
1960 }
1961
1962 /* Insert N characters. */
1963 static void
1964 vte_sequence_handler_IC(VteTerminal *terminal,
1965                         const char *match,
1966                         GQuark match_quark,
1967                         GValueArray *params)
1968 {
1969         vte_sequence_handler_multiple(terminal, match, match_quark, params,
1970                                       vte_sequence_handler_ic);
1971 }
1972
1973 /* Begin insert mode. */
1974 static void
1975 vte_sequence_handler_im(VteTerminal *terminal,
1976                         const char *match,
1977                         GQuark match_quark,
1978                         GValueArray *params)
1979 {
1980         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1981         terminal->pvt->screen->insert_mode = TRUE;
1982 }
1983
1984 /* Send me a backspace key sym, will you?  Guess that the application meant
1985  * to send the cursor back one position. */
1986 static void
1987 vte_sequence_handler_kb(VteTerminal *terminal,
1988                         const char *match,
1989                         GQuark match_quark,
1990                         GValueArray *params)
1991 {
1992         VteScreen *screen;
1993         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1994         screen = terminal->pvt->screen;
1995         if (screen->cursor_current.col > 0) {
1996                 /* There's room to move left, so do so. */
1997                 screen->cursor_current.col--;
1998         } else {
1999                 if (terminal->pvt->flags.bw) {
2000                         /* Wrap to the previous line. */
2001                         screen->cursor_current.col = terminal->column_count - 1;
2002                         screen->cursor_current.row = MAX(screen->cursor_current.row - 1,
2003                                                          screen->insert_delta);
2004                 } else {
2005                         /* Stick to the first column. */
2006                         screen->cursor_current.col = 0;
2007                 }
2008         }
2009 }
2010
2011 /* Keypad mode end. */
2012 static void
2013 vte_sequence_handler_ke(VteTerminal *terminal,
2014                         const char *match,
2015                         GQuark match_quark,
2016                         GValueArray *params)
2017 {
2018         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2019         terminal->pvt->keypad = VTE_KEYPAD_NORMAL;
2020 }
2021
2022 /* Keypad mode start. */
2023 static void
2024 vte_sequence_handler_ks(VteTerminal *terminal,
2025                         const char *match,
2026                         GQuark match_quark,
2027                         GValueArray *params)
2028 {
2029         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2030         terminal->pvt->keypad = VTE_KEYPAD_APPLICATION;
2031 }
2032
2033 /* Cursor left. */
2034 static void
2035 vte_sequence_handler_le(VteTerminal *terminal,
2036                         const char *match,
2037                         GQuark match_quark,
2038                         GValueArray *params)
2039 {
2040         vte_sequence_handler_kb(terminal, match, match_quark, params);
2041 }
2042
2043 /* Move the cursor left N columns. */
2044 static void
2045 vte_sequence_handler_LE(VteTerminal *terminal,
2046                         const char *match,
2047                         GQuark match_quark,
2048                         GValueArray *params)
2049 {
2050         vte_sequence_handler_multiple(terminal, match, match_quark, params,
2051                                       vte_sequence_handler_le);
2052 }
2053
2054 /* Move the cursor to the lower left corner of the display. */
2055 static void
2056 vte_sequence_handler_ll(VteTerminal *terminal,
2057                         const char *match,
2058                         GQuark match_quark,
2059                         GValueArray *params)
2060 {
2061         VteScreen *screen;
2062         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2063         screen = terminal->pvt->screen;
2064         screen->cursor_current.row = screen->insert_delta +
2065                                      terminal->row_count - 1;
2066         screen->cursor_current.col = 0;
2067 }
2068
2069 /* Blink on. */
2070 static void
2071 vte_sequence_handler_mb(VteTerminal *terminal,
2072                         const char *match,
2073                         GQuark match_quark,
2074                         GValueArray *params)
2075 {
2076         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2077         terminal->pvt->screen->defaults.blink = 1;
2078 }
2079
2080 /* Bold on. */
2081 static void
2082 vte_sequence_handler_md(VteTerminal *terminal,
2083                         const char *match,
2084                         GQuark match_quark,
2085                         GValueArray *params)
2086 {
2087         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2088         terminal->pvt->screen->defaults.bold = 1;
2089 }
2090
2091 /* End modes. */
2092 static void
2093 vte_sequence_handler_me(VteTerminal *terminal,
2094                         const char *match,
2095                         GQuark match_quark,
2096                         GValueArray *params)
2097 {
2098         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2099         vte_terminal_set_default_attributes(terminal);
2100 }
2101
2102 /* Half-bright on. */
2103 static void
2104 vte_sequence_handler_mh(VteTerminal *terminal,
2105                         const char *match,
2106                         GQuark match_quark,
2107                         GValueArray *params)
2108 {
2109         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2110         terminal->pvt->screen->defaults.half = 1;
2111 }
2112
2113 /* Invisible on. */
2114 static void
2115 vte_sequence_handler_mk(VteTerminal *terminal,
2116                         const char *match,
2117                         GQuark match_quark,
2118                         GValueArray *params)
2119 {
2120         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2121         terminal->pvt->screen->defaults.invisible = 1;
2122 }
2123
2124 /* Protect on. */
2125 static void
2126 vte_sequence_handler_mp(VteTerminal *terminal,
2127                         const char *match,
2128                         GQuark match_quark,
2129                         GValueArray *params)
2130 {
2131         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2132         terminal->pvt->screen->defaults.protect = 1;
2133 }
2134
2135 /* Reverse on. */
2136 static void
2137 vte_sequence_handler_mr(VteTerminal *terminal,
2138                         const char *match,
2139                         GQuark match_quark,
2140                         GValueArray *params)
2141 {
2142         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2143         terminal->pvt->screen->defaults.reverse = 1;
2144 }
2145
2146 /* Cursor right. */
2147 static void
2148 vte_sequence_handler_nd(VteTerminal *terminal,
2149                         const char *match,
2150                         GQuark match_quark,
2151                         GValueArray *params)
2152 {
2153         VteScreen *screen;
2154         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2155         screen = terminal->pvt->screen;
2156         if ((screen->cursor_current.col + 1) < terminal->column_count) {
2157                 /* Room to move right. */
2158                 screen->cursor_current.col++;
2159         } else {
2160                 /* Wrap? */
2161                 if (terminal->pvt->flags.am) {
2162                         /* Move on to the next line. */
2163                         screen->cursor_current.col = 0;
2164                         screen->cursor_current.row++;
2165                         /* Scroll to make the new line viewable if need be. */
2166                         vte_terminal_scroll_insertion(terminal);
2167                 } else {
2168                         /* Nope, peg to the rightmost column. */
2169                         screen->cursor_current.col = terminal->column_count - 1;
2170                 }
2171         }
2172 }
2173
2174 /* No-op. */
2175 static void
2176 vte_sequence_handler_noop(VteTerminal *terminal,
2177                           const char *match,
2178                           GQuark match_quark,
2179                           GValueArray *params)
2180 {
2181         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2182 }
2183
2184 /* Restore cursor (position). */
2185 static void
2186 vte_sequence_handler_rc(VteTerminal *terminal,
2187                         const char *match,
2188                         GQuark match_quark,
2189                         GValueArray *params)
2190 {
2191         VteScreen *screen;
2192         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2193         screen = terminal->pvt->screen;
2194         screen->cursor_current.col = screen->cursor_saved.col;
2195         screen->cursor_current.row = screen->cursor_saved.row +
2196                                      screen->insert_delta;
2197 }
2198
2199 /* Cursor right N characters. */
2200 static void
2201 vte_sequence_handler_RI(VteTerminal *terminal,
2202                         const char *match,
2203                         GQuark match_quark,
2204                         GValueArray *params)
2205 {
2206         vte_sequence_handler_multiple(terminal, match, match_quark, params,
2207                                       vte_sequence_handler_nd);
2208 }
2209
2210 /* Save cursor (position). */
2211 static void
2212 vte_sequence_handler_sc(VteTerminal *terminal,
2213                         const char *match,
2214                         GQuark match_quark,
2215                         GValueArray *params)
2216 {
2217         VteScreen *screen;
2218         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2219         screen = terminal->pvt->screen;
2220         screen->cursor_saved.col = screen->cursor_current.col;
2221         screen->cursor_saved.row = screen->cursor_current.row -
2222                                    screen->insert_delta;
2223 }
2224
2225 /* Standout end. */
2226 static void
2227 vte_sequence_handler_se(VteTerminal *terminal,
2228                         const char *match,
2229                         GQuark match_quark,
2230                         GValueArray *params)
2231 {
2232         char *bold, *underline, *standout, *reverse, *half, *blink;
2233         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2234
2235         /* Standout may be mapped to another attribute, so attempt to do
2236          * the Right Thing here. */
2237
2238         standout = vte_termcap_find_string(terminal->pvt->termcap,
2239                                            terminal->pvt->terminal,
2240                                            "so");
2241         g_assert(standout != NULL);
2242         blink = vte_termcap_find_string(terminal->pvt->termcap,
2243                                         terminal->pvt->terminal,
2244                                         "mb");
2245         bold = vte_termcap_find_string(terminal->pvt->termcap,
2246                                        terminal->pvt->terminal,
2247                                        "md");
2248         half = vte_termcap_find_string(terminal->pvt->termcap,
2249                                        terminal->pvt->terminal,
2250                                        "mh");
2251         reverse = vte_termcap_find_string(terminal->pvt->termcap,
2252                                           terminal->pvt->terminal,
2253                                           "mr");
2254         underline = vte_termcap_find_string(terminal->pvt->termcap,
2255                                             terminal->pvt->terminal,
2256                                             "us");
2257
2258         /* If the standout sequence is the same as another sequence, do what
2259          * we'd do for that other sequence instead. */
2260         if (blink && (g_ascii_strcasecmp(standout, blink) == 0)) {
2261                 vte_sequence_handler_me(terminal, match, match_quark, params);
2262         } else
2263         if (bold && (g_ascii_strcasecmp(standout, bold) == 0)) {
2264                 vte_sequence_handler_me(terminal, match, match_quark, params);
2265         } else
2266         if (half && (g_ascii_strcasecmp(standout, half) == 0)) {
2267                 vte_sequence_handler_me(terminal, match, match_quark, params);
2268         } else
2269         if (reverse && (g_ascii_strcasecmp(standout, reverse) == 0)) {
2270                 vte_sequence_handler_me(terminal, match, match_quark, params);
2271         } else
2272         if (underline && (g_ascii_strcasecmp(standout, underline) == 0)) {
2273                 vte_sequence_handler_ue(terminal, match, match_quark, params);
2274         } else {
2275                 /* Otherwise just set standout mode. */
2276                 terminal->pvt->screen->defaults.standout = 0;
2277         }
2278
2279         if (blink) {
2280                 g_free(blink);
2281         }
2282         if (bold) {
2283                 g_free(bold);
2284         }
2285         if (half) {
2286                 g_free(half);
2287         }
2288         if (reverse) {
2289                 g_free(reverse);
2290         }
2291         if (underline) {
2292                 g_free(underline);
2293         }
2294         g_free(standout);
2295 }
2296
2297 /* Standout start. */
2298 static void
2299 vte_sequence_handler_so(VteTerminal *terminal,
2300                         const char *match,
2301                         GQuark match_quark,
2302                         GValueArray *params)
2303 {
2304         char *bold, *underline, *standout, *reverse, *half, *blink;
2305         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2306
2307         /* Standout may be mapped to another attribute, so attempt to do
2308          * the Right Thing here. */
2309
2310         standout = vte_termcap_find_string(terminal->pvt->termcap,
2311                                            terminal->pvt->terminal,
2312                                            "so");
2313         g_assert(standout != NULL);
2314         blink = vte_termcap_find_string(terminal->pvt->termcap,
2315                                         terminal->pvt->terminal,
2316                                         "mb");
2317         bold = vte_termcap_find_string(terminal->pvt->termcap,
2318                                        terminal->pvt->terminal,
2319                                        "md");
2320         half = vte_termcap_find_string(terminal->pvt->termcap,
2321                                        terminal->pvt->terminal,
2322                                        "mh");
2323         reverse = vte_termcap_find_string(terminal->pvt->termcap,
2324                                           terminal->pvt->terminal,
2325                                           "mr");
2326         underline = vte_termcap_find_string(terminal->pvt->termcap,
2327                                             terminal->pvt->terminal,
2328                                             "us");
2329
2330         /* If the standout sequence is the same as another sequence, do what
2331          * we'd do for that other sequence instead. */
2332         if (blink && (g_ascii_strcasecmp(standout, blink) == 0)) {
2333                 vte_sequence_handler_mb(terminal, match, match_quark, params);
2334         } else
2335         if (bold && (g_ascii_strcasecmp(standout, bold) == 0)) {
2336                 vte_sequence_handler_md(terminal, match, match_quark, params);
2337         } else
2338         if (half && (g_ascii_strcasecmp(standout, half) == 0)) {
2339                 vte_sequence_handler_mh(terminal, match, match_quark, params);
2340         } else
2341         if (reverse && (g_ascii_strcasecmp(standout, reverse) == 0)) {
2342                 vte_sequence_handler_mr(terminal, match, match_quark, params);
2343         } else
2344         if (underline && (g_ascii_strcasecmp(standout, underline) == 0)) {
2345                 vte_sequence_handler_us(terminal, match, match_quark, params);
2346         } else {
2347                 /* Otherwise just set standout mode. */
2348                 terminal->pvt->screen->defaults.standout = 1;
2349         }
2350
2351         if (blink) {
2352                 g_free(blink);
2353         }
2354         if (bold) {
2355                 g_free(bold);
2356         }
2357         if (half) {
2358                 g_free(half);
2359         }
2360         if (reverse) {
2361                 g_free(reverse);
2362         }
2363         if (underline) {
2364                 g_free(underline);
2365         }
2366         g_free(standout);
2367 }
2368
2369 /* Set tab stop in the current column. */
2370 static void
2371 vte_sequence_handler_st(VteTerminal *terminal,
2372                         const char *match,
2373                         GQuark match_quark,
2374                         GValueArray *params)
2375 {
2376         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2377         if (terminal->pvt->tabstops == NULL) {
2378                 terminal->pvt->tabstops = g_hash_table_new(g_direct_hash,
2379                                                            g_direct_equal);
2380         }
2381         vte_terminal_set_tabstop(terminal,
2382                                  terminal->pvt->screen->cursor_current.col);
2383 }
2384
2385 /* Tab. */
2386 static void
2387 vte_sequence_handler_ta(VteTerminal *terminal,
2388                         const char *match,
2389                         GQuark match_quark,
2390                         GValueArray *params)
2391 {
2392         long newcol;
2393         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2394
2395         /* Calculate which column is the next tab stop. */
2396         newcol = terminal->pvt->screen->cursor_current.col;
2397
2398         if (terminal->pvt->tabstops != NULL) {
2399                 /* Find the next tabstop. */
2400                 for (newcol++; newcol < VTE_TAB_MAX; newcol++) {
2401                         if (vte_terminal_get_tabstop(terminal, newcol)) {
2402                                 break;
2403                         }
2404                 }
2405         }
2406
2407         /* If we have no tab stops, stop at the right-most column. */
2408         if (newcol >= VTE_TAB_MAX) {
2409                 newcol = terminal->column_count - 1;
2410         }
2411
2412         /* Wrap to the next line if need be. */
2413         if (newcol >= terminal->column_count) {
2414                 if (terminal->pvt->flags.am) {
2415                         /* Move to the next line. */
2416                         terminal->pvt->screen->cursor_current.col = 0;
2417                         vte_sequence_handler_do(terminal, match,
2418                                                 match_quark, params);
2419                 } else {
2420                         /* Stay in the rightmost column. */
2421                         newcol = terminal->column_count - 1;
2422                 }
2423         } else {
2424                 terminal->pvt->screen->cursor_current.col = newcol;
2425         }
2426 #ifdef VTE_DEBUG
2427         if (vte_debug_on(VTE_DEBUG_PARSE)) {
2428                 fprintf(stderr, "Moving cursor to column %ld.\n", (long)newcol);
2429         }
2430 #endif
2431 }
2432
2433 /* Clear tabs selectively. */
2434 static void
2435 vte_sequence_handler_tab_clear(VteTerminal *terminal,
2436                                const char *match,
2437                                GQuark match_quark,
2438                                GValueArray *params)
2439 {
2440         GValue *value;
2441         long param = 0;
2442         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2443         if ((params != NULL) && (params->n_values > 0)) {
2444                 value = g_value_array_get_nth(params, 0);
2445                 if (G_VALUE_HOLDS_LONG(value)) {
2446                         param = g_value_get_long(value);
2447                 }
2448         }
2449         if (param == 0) {
2450                 vte_terminal_clear_tabstop(terminal,
2451                                            terminal->pvt->screen->cursor_current.col);
2452         } else
2453         if (param == 3) {
2454                 if (terminal->pvt->tabstops != NULL) {
2455                         g_hash_table_destroy(terminal->pvt->tabstops);
2456                         terminal->pvt->tabstops = NULL;
2457                 }
2458         }
2459 }
2460
2461 /* Terminal usage starts. */
2462 static void
2463 vte_sequence_handler_ts(VteTerminal *terminal,
2464                         const char *match,
2465                         GQuark match_quark,
2466                         GValueArray *params)
2467 {
2468         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2469         /* I think this is a no-op. */
2470 }
2471
2472 /* Underline this character and move right. */
2473 static void
2474 vte_sequence_handler_uc(VteTerminal *terminal,
2475                         const char *match,
2476                         GQuark match_quark,
2477                         GValueArray *params)
2478 {
2479         struct vte_charcell *cell;
2480         VteScreen *screen;
2481         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2482         screen = terminal->pvt->screen;
2483         cell = vte_terminal_find_charcell(terminal,
2484                                           screen->cursor_current.col,
2485                                           screen->cursor_current.row);
2486         if (cell != NULL) {
2487                 /* Set this character to be underlined. */
2488                 cell->underline = 1;
2489                 /* Cause it to be repainted. */
2490                 vte_invalidate_cells(terminal,
2491                                      screen->cursor_current.col, 2,
2492                                      screen->cursor_current.row, 1);
2493                 /* Move the cursor right. */
2494                 vte_sequence_handler_nd(terminal, match, match_quark, params);
2495         }
2496 }
2497
2498 /* Underline end. */
2499 static void
2500 vte_sequence_handler_ue(VteTerminal *terminal,
2501                         const char *match,
2502                         GQuark match_quark,
2503                         GValueArray *params)
2504 {
2505         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2506         terminal->pvt->screen->defaults.underline = 0;
2507 }
2508
2509 /* Cursor up, scrolling if need be. */
2510 static void
2511 vte_sequence_handler_up(VteTerminal *terminal,
2512                         const char *match,
2513                         GQuark match_quark,
2514                         GValueArray *params)
2515 {
2516         GtkWidget *widget;
2517         long col, row, start, end;
2518         VteScreen *screen;
2519
2520         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2521         widget = GTK_WIDGET(terminal);
2522         screen = terminal->pvt->screen;
2523
2524         col = screen->cursor_current.col;
2525         row = screen->cursor_current.row;
2526
2527         if (screen->scrolling_restricted) {
2528                 start = screen->scrolling_region.start + screen->insert_delta;
2529                 end = screen->scrolling_region.end + screen->insert_delta;
2530                 if (row == start) {
2531                         /* If we're at the top of the scrolling region, add a
2532                          * line at the top to scroll the bottom off. */
2533                         vte_remove_line_int(terminal, end);
2534                         vte_insert_line_int(terminal, start);
2535                         if ((terminal->pvt->bg_image == NULL) &&
2536                             (!terminal->pvt->bg_transparent)) {
2537 #if 0
2538                                 /* Scroll the window. */
2539                                 gdk_window_scroll(widget->window,
2540                                                   0,
2541                                                   terminal->char_height);
2542                                 /* We need to redraw the first row of the
2543                                  * scrolling region, and anything above. */
2544                                 vte_invalidate_cells(terminal,
2545                                                      0, terminal->column_count,
2546                                                      0, start + 1);
2547                                 /* Also redraw anything below the scrolling
2548                                  * region. */
2549                                 vte_invalidate_cells(terminal,
2550                                                      0, terminal->column_count,
2551                                                      end, terminal->row_count);
2552 #endif
2553                                 vte_invalidate_cells(terminal,
2554                                                      0, terminal->column_count,
2555                                                      start, end - start + 1);
2556                         } else {
2557                                 /* If we have a background image, we need to
2558                                  * redraw the entire window. */
2559                                 vte_invalidate_cells(terminal,
2560                                                      0, terminal->column_count,
2561                                                      start, end - start + 1);
2562                         }
2563                 } else {
2564                         /* Otherwise, just move the cursor up. */
2565                         screen->cursor_current.row--;
2566                         row = screen->cursor_current.row;
2567                 }
2568         } else {
2569                 start = terminal->pvt->screen->insert_delta;
2570                 end = start + terminal->row_count - 1;
2571                 if (row == start) {
2572                         /* Insert a blank line and remove one from the bottom,
2573                          * to simulate a proper scroll without screwing up the
2574                          * history. */
2575                         vte_remove_line_int(terminal, end);
2576                         vte_insert_line_int(terminal, start);
2577                         if ((terminal->pvt->bg_image == NULL) &&
2578                             (!terminal->pvt->bg_transparent)) {
2579 #if 0
2580                                 /* Scroll the window. */
2581                                 gdk_window_scroll(widget->window,
2582                                                   0,
2583                                                   terminal->char_height);
2584                                 /* We need to redraw the bottom row. */
2585                                 vte_invalidate_cells(terminal,
2586                                                      0,
2587                                                      terminal->column_count,
2588                                                      terminal->row_count - 1,
2589                                                      1);
2590 #else
2591                                 vte_invalidate_all(terminal);
2592 #endif
2593                         } else {
2594                                 /* If we have a background image, we need to
2595                                  * redraw the entire window. */
2596                                 vte_invalidate_all(terminal);
2597                         }
2598                 } else {
2599                         /* Move the cursor up. */
2600                         screen->cursor_current.row--;
2601                         row = screen->cursor_current.row;
2602                 }
2603         }
2604 }
2605
2606 /* Cursor up. */
2607 static void
2608 vte_sequence_handler_UP(VteTerminal *terminal,
2609                         const char *match,
2610                         GQuark match_quark,
2611                         GValueArray *params)
2612 {
2613         vte_sequence_handler_multiple(terminal, match, match_quark, params,
2614                                       vte_sequence_handler_up);
2615 }
2616
2617 /* Underline start. */
2618 static void
2619 vte_sequence_handler_us(VteTerminal *terminal,
2620                         const char *match,
2621                         GQuark match_quark,
2622                         GValueArray *params)
2623 {
2624         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2625         terminal->pvt->screen->defaults.underline = 1;
2626 }
2627
2628 /* Visible bell. */
2629 static void
2630 vte_sequence_handler_vb(VteTerminal *terminal,
2631                         const char *match,
2632                         GQuark match_quark,
2633                         GValueArray *params)
2634 {
2635         Display *display;
2636         GdkDrawable *gdrawable;
2637         Drawable drawable;
2638         GC gc;
2639         gint x_offs, y_offs;
2640
2641         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2642
2643         if (GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
2644                 /* Fill the screen with the default foreground color, and then
2645                  * repaint everything, to provide visual bell. */
2646                 gdk_window_get_internal_paint_info(GTK_WIDGET(terminal)->window,
2647                                                    &gdrawable,
2648                                                    &x_offs,
2649                                                    &y_offs);
2650                 display = gdk_x11_drawable_get_xdisplay(gdrawable);
2651                 drawable = gdk_x11_drawable_get_xid(gdrawable);
2652                 gc = XCreateGC(display, drawable, 0, NULL);
2653
2654                 XSetForeground(display, gc,
2655                                terminal->pvt->palette[VTE_DEF_FG].pixel);
2656                 XFillRectangle(display, drawable, gc,
2657                                x_offs, y_offs,
2658                                terminal->column_count * terminal->char_width,
2659                                terminal->row_count * terminal->char_height);
2660                 gdk_window_process_all_updates();
2661
2662                 vte_invalidate_all(terminal);
2663                 gdk_window_process_all_updates();
2664         }
2665 }
2666
2667 /* Cursor visible. */
2668 static void
2669 vte_sequence_handler_ve(VteTerminal *terminal,
2670                         const char *match,
2671                         GQuark match_quark,
2672                         GValueArray *params)
2673 {
2674         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2675         terminal->pvt->screen->cursor_visible = TRUE;
2676 }
2677
2678 /* Cursor invisible. */
2679 static void
2680 vte_sequence_handler_vi(VteTerminal *terminal,
2681                         const char *match,
2682                         GQuark match_quark,
2683                         GValueArray *params)
2684 {
2685         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2686         terminal->pvt->screen->cursor_visible = FALSE;
2687 }
2688
2689 /* Cursor standout. */
2690 static void
2691 vte_sequence_handler_vs(VteTerminal *terminal,
2692                         const char *match,
2693                         GQuark match_quark,
2694                         GValueArray *params)
2695 {
2696         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2697         terminal->pvt->screen->cursor_visible = TRUE; /* FIXME: should be
2698                                                          *more* visible. */
2699 }
2700
2701 /* Handle ANSI color setting and related stuffs (SGR). */
2702 static void
2703 vte_sequence_handler_character_attributes(VteTerminal *terminal,
2704                                           const char *match,
2705                                           GQuark match_quark,
2706                                           GValueArray *params)
2707 {
2708         unsigned int i;
2709         GValue *value;
2710         long param;
2711         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2712         /* The default parameter is zero. */
2713         param = 0;
2714         /* Step through each numeric parameter. */
2715         for (i = 0; (params != NULL) && (i < params->n_values); i++) {
2716                 /* If this parameter isn't a number, skip it. */
2717                 value = g_value_array_get_nth(params, i);
2718                 if (!G_VALUE_HOLDS_LONG(value)) {
2719                         continue;
2720                 }
2721                 param = g_value_get_long(value);
2722                 switch (param) {
2723                         case 0:
2724                                 vte_terminal_set_default_attributes(terminal);
2725                                 break;
2726                         case 1:
2727                                 terminal->pvt->screen->defaults.bold = 1;
2728                                 break;
2729                         case 4:
2730                                 terminal->pvt->screen->defaults.underline = 1;
2731                                 break;
2732                         case 5:
2733                                 terminal->pvt->screen->defaults.blink = 1;
2734                                 break;
2735                         case 7:
2736                                 terminal->pvt->screen->defaults.reverse = 1;
2737                                 break;
2738                         case 8:
2739                                 terminal->pvt->screen->defaults.invisible = 1;
2740                                 break;
2741                         case 21: /* one of these is the linux console */
2742                         case 22: /* one of these is ecma, i forget which */
2743                                 terminal->pvt->screen->defaults.bold = 0;
2744                                 break;
2745                         case 24:
2746                                 terminal->pvt->screen->defaults.underline = 0;
2747                                 break;
2748                         case 25:
2749                                 terminal->pvt->screen->defaults.blink = 0;
2750                                 break;
2751                         case 27:
2752                                 terminal->pvt->screen->defaults.reverse = 0;
2753                                 break;
2754                         case 28:
2755                                 terminal->pvt->screen->defaults.invisible = 0;
2756                                 break;
2757                         case 30:
2758                         case 31:
2759                         case 32:
2760                         case 33:
2761                         case 34:
2762                         case 35:
2763                         case 36:
2764                         case 37:
2765                                 terminal->pvt->screen->defaults.fore = param - 30;
2766                                 break;
2767                         case 38:
2768                                 /* default foreground, underscore */
2769                                 terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
2770                                 terminal->pvt->screen->defaults.underline = 1;
2771                                 break;
2772                         case 39:
2773                                 /* default foreground, no underscore */
2774                                 terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
2775                                 terminal->pvt->screen->defaults.underline = 0;
2776                                 break;
2777                         case 40:
2778                         case 41:
2779                         case 42:
2780                         case 43:
2781                         case 44:
2782                         case 45:
2783                         case 46:
2784                         case 47:
2785                                 terminal->pvt->screen->defaults.back = param - 40;
2786                                 break;
2787                         case 49:
2788                                 /* default background */
2789                                 terminal->pvt->screen->defaults.back = VTE_DEF_BG;
2790                                 break;
2791                         case 90:
2792                         case 91:
2793                         case 92:
2794                         case 93:
2795                         case 94:
2796                         case 95:
2797                         case 96:
2798                         case 97:
2799                                 terminal->pvt->screen->defaults.fore = param - 90;
2800                                 break;
2801                         case 100:
2802                         case 101:
2803                         case 102:
2804                         case 103:
2805                         case 104:
2806                         case 105:
2807                         case 106:
2808                         case 107:
2809                                 terminal->pvt->screen->defaults.back = param - 100;
2810                                 break;
2811                 }
2812         }
2813         /* If we had no parameters, default to the defaults. */
2814         if (i == 0) {
2815                 vte_terminal_set_default_attributes(terminal);
2816         }
2817 }
2818
2819 /* Clear above the current line. */
2820 static void
2821 vte_sequence_handler_clear_above_current(VteTerminal *terminal,
2822                                          const char *match,
2823                                          GQuark match_quark,
2824                                          GValueArray *params)
2825 {
2826         GArray *rowdata;
2827         long i;
2828         VteScreen *screen;
2829         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2830         screen = terminal->pvt->screen;
2831         /* If the cursor is actually on the screen, clear data in the row
2832          * which corresponds to the cursor. */
2833         for (i = screen->insert_delta; i < screen->cursor_current.row; i++) {
2834                 if (vte_ring_next(screen->row_data) > i) {
2835                         /* Get the data for the row we're erasing. */
2836                         rowdata = vte_ring_index(screen->row_data, GArray*, i);
2837                         /* Remove it. */
2838                         while (rowdata->len > 0) {
2839                                 g_array_remove_index(rowdata, rowdata->len - 1);
2840                         }
2841                         /* Repaint this row. */
2842                         vte_invalidate_cells(terminal,
2843                                              0, terminal->column_count,
2844                                              i, 1);
2845                 }
2846         }
2847 }
2848
2849 /* Clear the entire screen. */
2850 static void
2851 vte_sequence_handler_clear_screen(VteTerminal *terminal,
2852                                   const char *match,
2853                                   GQuark match_quark,
2854                                   GValueArray *params)
2855 {
2856         GArray *rowdata;
2857         long i;
2858         VteScreen *screen;
2859         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2860         screen = terminal->pvt->screen;
2861         /* Clear the data in all of the visible rows. */
2862         for (i = screen->insert_delta;
2863              i < screen->insert_delta + terminal->row_count;
2864              i++) {
2865                 if (vte_ring_contains(screen->row_data, i)) {
2866                         /* Get the data for the row we're removing. */
2867                         rowdata = vte_ring_index(screen->row_data, GArray*, i);
2868                         /* Remove it. */
2869                         while (rowdata->len > 0) {
2870                                 g_array_remove_index(rowdata, rowdata->len - 1);
2871                         }
2872                         /* Repaint this row. */
2873                         vte_invalidate_cells(terminal,
2874                                              0, terminal->column_count,
2875                                              i, 1);
2876                 }
2877         }
2878 }
2879
2880 /* Move the cursor to the given column, 1-based. */
2881 static void
2882 vte_sequence_handler_cursor_character_absolute(VteTerminal *terminal,
2883                                                const char *match,
2884                                                GQuark match_quark,
2885                                                GValueArray *params)
2886 {
2887         vte_sequence_handler_offset(terminal, match, match_quark, params,
2888                                     -1, vte_sequence_handler_ch);
2889 }
2890
2891 /* Move the cursor to the given position, 1-based. */
2892 static void
2893 vte_sequence_handler_cursor_position(VteTerminal *terminal,
2894                                      const char *match,
2895                                      GQuark match_quark,
2896                                      GValueArray *params)
2897 {
2898         vte_sequence_handler_offset(terminal, match, match_quark, params,
2899                                     -1, vte_sequence_handler_cm);
2900 }
2901
2902 /* Set icon/window titles. */
2903 static void
2904 vte_sequence_handler_set_title_int(VteTerminal *terminal,
2905                                    const char *match,
2906                                    GQuark match_quark,
2907                                    GValueArray *params,
2908                                    const char *signal)
2909 {
2910         GValue *value;
2911         iconv_t conv;
2912         char *inbuf = NULL, *outbuf = NULL, *outbufptr = NULL;
2913         size_t inbuf_len, outbuf_len;
2914         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2915         /* Get the string parameter's value. */
2916         value = g_value_array_get_nth(params, 0);
2917         if (value) {
2918                 if (G_VALUE_HOLDS_LONG(value)) {
2919                         /* Convert the long to a string. */
2920                         outbufptr = g_strdup_printf("%ld",
2921                                                     g_value_get_long(value));
2922                 } else
2923                 if (G_VALUE_HOLDS_STRING(value)) {
2924                         /* Copy the string into the buffer. */
2925                         outbufptr = g_value_dup_string(value);
2926                 } else
2927                 if (G_VALUE_HOLDS_POINTER(value)) {
2928                         /* Convert the wide-character string into a
2929                          * multibyte string. */
2930                         conv = iconv_open("UTF-8", "WCHAR_T");
2931                         inbuf = g_value_get_pointer(value);
2932                         inbuf_len = wcslen((wchar_t*)inbuf) * sizeof(wchar_t);
2933                         outbuf_len = (inbuf_len * VTE_UTF8_BPC) + 1;
2934                         outbuf = outbufptr = g_malloc0(outbuf_len);
2935                         if (iconv(conv, &inbuf, &inbuf_len,
2936                                   &outbuf, &outbuf_len) == -1) {
2937 #ifdef VTE_DEBUG
2938                                 if (vte_debug_on(VTE_DEBUG_IO)) {
2939                                         fprintf(stderr, "Error converting %ld "
2940                                                 "title bytes (%s), skipping.\n",
2941                                                 (long) terminal->pvt->n_outgoing,
2942                                                 strerror(errno));
2943                                 }
2944 #endif
2945                                 g_free(outbufptr);
2946                                 outbufptr = NULL;
2947                         }
2948                 }
2949                 if (outbufptr != NULL) {
2950                         /* Emit the signal */
2951                         if (strcmp(signal, "window_title_changed") == 0) {
2952                                 g_free(terminal->window_title);
2953                                 terminal->window_title = outbufptr;
2954                                 vte_terminal_emit_window_title_changed(terminal);
2955                         }
2956                         else if (strcmp (signal, "icon_title_changed") == 0) {
2957                                 g_free (terminal->icon_title);
2958                                 terminal->icon_title = outbufptr;
2959                                 vte_terminal_emit_icon_title_changed(terminal);
2960                         }
2961                 }
2962         }
2963 }
2964
2965 /* Set one or the other. */
2966 static void
2967 vte_sequence_handler_set_icon_title(VteTerminal *terminal,
2968                                     const char *match,
2969                                     GQuark match_quark,
2970                                     GValueArray *params)
2971 {
2972         vte_sequence_handler_set_title_int(terminal, match, match_quark,
2973                                            params, "icon_title_changed");
2974 }
2975 static void
2976 vte_sequence_handler_set_window_title(VteTerminal *terminal,
2977                                       const char *match,
2978                                       GQuark match_quark,
2979                                       GValueArray *params)
2980 {
2981         vte_sequence_handler_set_title_int(terminal, match, match_quark,
2982                                            params, "window_title_changed");
2983 }
2984
2985 /* Set both the window and icon titles to the same string. */
2986 static void
2987 vte_sequence_handler_set_icon_and_window_title(VteTerminal *terminal,
2988                                                   const char *match,
2989                                                   GQuark match_quark,
2990                                                   GValueArray *params)
2991 {
2992         vte_sequence_handler_set_title_int(terminal, match, match_quark,
2993                                            params, "icon_title_changed");
2994         vte_sequence_handler_set_title_int(terminal, match, match_quark,
2995                                            params, "window_title_changed");
2996 }
2997
2998 /* Restrict the scrolling region. */
2999 static void
3000 vte_sequence_handler_set_scrolling_region(VteTerminal *terminal,
3001                                           const char *match,
3002                                           GQuark match_quark,
3003                                           GValueArray *params)
3004 {
3005         vte_sequence_handler_offset(terminal, match, match_quark, params,
3006                                     -1, vte_sequence_handler_cs);
3007 }
3008
3009 /* Show or hide the pointer. */
3010 static void
3011 vte_terminal_set_pointer_visible(VteTerminal *terminal, gboolean visible)
3012 {
3013         GdkCursor *cursor = NULL;
3014         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3015         if (visible || !terminal->pvt->mouse_autohide) {
3016                 if (terminal->pvt->mouse_send_xy_on_click ||
3017                     terminal->pvt->mouse_send_xy_on_button ||
3018                     terminal->pvt->mouse_hilite_tracking ||
3019                     terminal->pvt->mouse_cell_motion_tracking ||
3020                     terminal->pvt->mouse_all_motion_tracking) {
3021 #ifdef VTE_DEBUG
3022                         if (vte_debug_on(VTE_DEBUG_IO)) {
3023                                 fprintf(stderr, "Setting mousing cursor.\n");
3024                         }
3025 #endif
3026                         cursor = terminal->pvt->mouse_mousing_cursor;
3027                 } else {
3028 #ifdef VTE_DEBUG
3029                         if (vte_debug_on(VTE_DEBUG_IO)) {
3030                                 fprintf(stderr, "Setting default mouse "
3031                                         "cursor.\n");
3032                         }
3033 #endif
3034                         cursor = terminal->pvt->mouse_default_cursor;
3035                 }
3036         } else {
3037 #ifdef VTE_DEBUG
3038                 if (vte_debug_on(VTE_DEBUG_IO)) {
3039                         fprintf(stderr, "Setting to invisible cursor.\n");
3040                 }
3041 #endif
3042                 cursor = terminal->pvt->mouse_inviso_cursor;
3043         }
3044         if (cursor) {
3045                 if (GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
3046                         gdk_window_set_cursor((GTK_WIDGET(terminal))->window,
3047                                               cursor);
3048                 }
3049         }
3050 }
3051
3052 /* Manipulate certain terminal attributes. */
3053 static void
3054 vte_sequence_handler_decset_internal(VteTerminal *terminal,
3055                                      int setting,
3056                                      gboolean restore,
3057                                      gboolean save,
3058                                      gboolean set)
3059 {
3060         gpointer p;
3061         int i;
3062         struct {
3063                 int setting;
3064                 gboolean *bvalue;
3065                 gint *ivalue;
3066                 gpointer *pvalue;
3067                 gpointer fvalue;
3068                 gpointer tvalue;
3069         } settings[] = {
3070                 /* Application/normal keypad. */
3071                 {1, NULL, &terminal->pvt->keypad, NULL,
3072                  GINT_TO_POINTER(VTE_KEYPAD_NORMAL),
3073                  GINT_TO_POINTER(VTE_KEYPAD_APPLICATION),},
3074                 /* Reverse video. */
3075                 {5, &terminal->pvt->screen->reverse_mode, NULL, NULL,
3076                  GINT_TO_POINTER(FALSE),
3077                  GINT_TO_POINTER(TRUE),},
3078                 /* Send-coords-on-click. */
3079                 {9, &terminal->pvt->mouse_send_xy_on_click, NULL, NULL,
3080                  GINT_TO_POINTER(FALSE),
3081                  GINT_TO_POINTER(TRUE),},
3082                 /* Cursor visible. */
3083                 {25, &terminal->pvt->screen->cursor_visible, NULL, NULL,
3084                  GINT_TO_POINTER(FALSE),
3085                  GINT_TO_POINTER(TRUE),},
3086                 /* Alternate screen. */
3087                 {47, NULL, NULL, (gpointer*) &terminal->pvt->screen,
3088                  &terminal->pvt->normal_screen,
3089                  &terminal->pvt->alternate_screen,},
3090                 /* Send-coords-on-button. */
3091                 {1000, &terminal->pvt->mouse_send_xy_on_button, NULL, NULL,
3092                  GINT_TO_POINTER(FALSE),
3093                  GINT_TO_POINTER(TRUE),},
3094                 /* Hilite tracking*/
3095                 {1001, &terminal->pvt->mouse_hilite_tracking, NULL, NULL,
3096                  GINT_TO_POINTER(FALSE),
3097                  GINT_TO_POINTER(TRUE),},
3098                 /* Cell motion tracking*/
3099                 {1002, &terminal->pvt->mouse_cell_motion_tracking, NULL, NULL,
3100                  GINT_TO_POINTER(FALSE),
3101                  GINT_TO_POINTER(TRUE),},
3102                 /* All motion tracking*/
3103                 {1003, &terminal->pvt->mouse_all_motion_tracking, NULL, NULL,
3104                  GINT_TO_POINTER(FALSE),
3105                  GINT_TO_POINTER(TRUE),},
3106         };
3107
3108         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3109
3110         /* Handle the setting. */
3111         for (i = 0; i < G_N_ELEMENTS(settings); i++)
3112         if (settings[i].setting == setting) {
3113                 /* Read the old setting. */
3114                 if (restore) {
3115                         p = g_hash_table_lookup(terminal->pvt->dec_saved,
3116                                                 GINT_TO_POINTER(setting));
3117                         set = (p != NULL);
3118 #ifdef VTE_DEBUG
3119                         if (vte_debug_on(VTE_DEBUG_PARSE)) {
3120                                 fprintf(stderr, "Setting %d was %s.\n",
3121                                         setting, set ? "set" : "unset");
3122                         }
3123 #endif
3124                 }
3125                 /* Save the current setting. */
3126                 if (save) {
3127                         if (settings[i].bvalue) {
3128                                 set = *(settings[i].bvalue) != FALSE;
3129                         } else
3130                         if (settings[i].ivalue) {
3131                                 set = *(settings[i].ivalue) ==
3132                                       GPOINTER_TO_INT(settings[i].tvalue);
3133                         } else
3134                         if (settings[i].pvalue) {
3135                                 set = *(settings[i].pvalue) ==
3136                                       settings[i].tvalue;
3137                         }
3138 #ifdef VTE_DEBUG
3139                         if (vte_debug_on(VTE_DEBUG_PARSE)) {
3140                                 fprintf(stderr, "Setting %d is %s, saving.\n",
3141                                         setting, set ? "set" : "unset");
3142                         }
3143 #endif
3144                         g_hash_table_insert(terminal->pvt->dec_saved,
3145                                             GINT_TO_POINTER(setting),
3146                                             GINT_TO_POINTER(set));
3147                 }
3148                 /* Change the current setting to match the new/saved value. */
3149                 if (!save) {
3150 #ifdef VTE_DEBUG
3151                         if (vte_debug_on(VTE_DEBUG_PARSE)) {
3152                                 fprintf(stderr, "Setting %d to %s.\n",
3153                                         setting, set ? "set" : "unset");
3154                         }
3155 #endif
3156                         if (settings[i].bvalue) {
3157                                 *(settings[i].bvalue) = set;
3158                         } else
3159                         if (settings[i].ivalue) {
3160                                 *(settings[i].ivalue) = set ?
3161                                         GPOINTER_TO_INT(settings[i].tvalue) :
3162                                         GPOINTER_TO_INT(settings[i].fvalue);
3163                         } else
3164                         if (settings[i].pvalue) {
3165                                 *(settings[i].pvalue) = set ?
3166                                         settings[i].tvalue :
3167                                         settings[i].fvalue;
3168                         }
3169                 }
3170         }
3171
3172         /* Do whatever's necessary when the setting changes. */
3173         switch (setting) {
3174                 case 5:
3175                         /* Repaint everything in reverse mode. */
3176                         vte_invalidate_all(terminal);
3177                         break;
3178                 case 25:
3179                         /* Repaint the cell the cursor is in. */
3180                         vte_invalidate_cursor_once(terminal);
3181                         break;
3182                 case 47:
3183                         /* Reset scrollbars and repaint everything. */
3184                         vte_terminal_adjust_adjustments(terminal);
3185                         vte_invalidate_all(terminal);
3186                         break;
3187                 case 9:
3188                 case 1000:
3189                 case 1001:
3190                 case 1002:
3191                 case 1003:
3192                         /* Make the pointer visible. */
3193                         vte_terminal_set_pointer_visible(terminal, TRUE);
3194                         break;
3195                 default:
3196                         break;
3197         }
3198 }
3199
3200 /* Set the application or normal keypad. */
3201 static void
3202 vte_sequence_handler_application_keypad(VteTerminal *terminal,
3203                                         const char *match,
3204                                         GQuark match_quark,
3205                                         GValueArray *params)
3206 {
3207         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3208         terminal->pvt->keypad = VTE_KEYPAD_APPLICATION;
3209 }
3210
3211 static void
3212 vte_sequence_handler_normal_keypad(VteTerminal *terminal,
3213                                    const char *match,
3214                                    GQuark match_quark,
3215                                    GValueArray *params)
3216 {
3217         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3218         terminal->pvt->keypad = VTE_KEYPAD_NORMAL;
3219 }
3220
3221 /* Move the cursor. */
3222 static void
3223 vte_sequence_handler_character_position_absolute(VteTerminal *terminal,
3224                                                  const char *match,
3225                                                  GQuark match_quark,
3226                                                  GValueArray *params)
3227 {
3228         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3229         vte_sequence_handler_offset(terminal, match, match_quark, params,
3230                                     -1, vte_sequence_handler_ch);
3231 }
3232 static void
3233 vte_sequence_handler_line_position_absolute(VteTerminal *terminal,
3234                                             const char *match,
3235                                             GQuark match_quark,
3236                                             GValueArray *params)
3237 {
3238         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3239         vte_sequence_handler_offset(terminal, match, match_quark, params,
3240                                     -1, vte_sequence_handler_cv);
3241 }
3242
3243 /* Set certain terminal attributes. */
3244 static void
3245 vte_sequence_handler_decset(VteTerminal *terminal,
3246                             const char *match,
3247                             GQuark match_quark,
3248                             GValueArray *params)
3249 {
3250         GValue *value;
3251         long setting;
3252         int i;
3253         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3254         if ((params == NULL) || (params->n_values == 0)) {
3255                 return;
3256         }
3257         for (i = 0; i < params->n_values; i++) {
3258                 value = g_value_array_get_nth(params, i);
3259                 if (!G_VALUE_HOLDS_LONG(value)) {
3260                         continue;
3261                 }
3262                 setting = g_value_get_long(value);
3263                 vte_sequence_handler_decset_internal(terminal, setting,
3264                                                      FALSE, FALSE, TRUE);
3265         }
3266 }
3267
3268 /* Unset certain terminal attributes. */
3269 static void
3270 vte_sequence_handler_decreset(VteTerminal *terminal,
3271                               const char *match,
3272                               GQuark match_quark,
3273                               GValueArray *params)
3274 {
3275         GValue *value;
3276         long setting;
3277         int i;
3278         g_return_if_fail(VTE_IS_TERMINAL(terminal));
3279         if ((params == NULL) || (params->n_values == 0)) {
3280                 return;
3281         }
3282         for (i = 0; i < params->n_values; i++) {
3283                 value = g_value_array_get_nth(params, i);
3284                 if (!G_VALUE_HOLDS_LONG(value)) {
3285                         continue;
3286                 }
3287                 setting = g_value_get_long(value);
3288                 vte_sequence_handler_decset_internal(terminal, setting,
3289                                                      FALSE, FALSE, FALSE);
3290         }
3291 }
3292
3293 /* Erase certain lines in the display. */
3294 static void
3295 vte_sequence_handler_erase_in_display(VteTerminal *terminal,
3296                                       const char *match,
3297                                       GQuark match_quark,
3298                                       GValueArray *params)
3299 {
3300         GValue *value;
3301         long param;
3302         int i;
3303         /* The default parameter is 0. */
3304         param = 0;
3305         /* Pull out a parameter. */
3306         for (i = 0; (params != NULL) && (i < params->n_values); i++) {
3307                 value = g_value_array_get_nth(params, i);
3308                 if (!G_VALUE_HOLDS_LONG(value)) {
3309                         continue;
3310                 }
3311                 param = g_value_get_long(value);
3312         }
3313         /* Clear the right area. */
3314         switch (param) {
3315                 case 0:
3316                         /* Clear below the current line. */
3317                         vte_sequence_handler_cd(terminal, NULL, 0, NULL);
3318                         break;
3319                 case 1:
3320                         /* Clear above the current line. */
3321                         vte_sequence_handler_clear_above_current(terminal,
3322                                                                  NULL,
3323                                                                  0,
3324                                                                  NULL);
3325                         break;
3326                 case 2:
3327                         /* Clear the entire screen. */
3328                         vte_sequence_handler_clear_screen(terminal,
3329                                                           NULL,
3330                                                           0,
3331                                                           NULL);
3332                         break;
3333                 default:
3334                         break;
3335         }
3336 }
3337
3338 /* Erase certain parts of the current line in the display. */
3339 static void
3340 vte_sequence_handler_erase_in_line(VteTerminal *terminal,
3341                                    const char *match,
3342                                    GQuark match_quark,
3343                                    GValueArray *params)
3344 {
3345         GValue *value;
3346         long param;
3347         int i;
3348         /* The default parameter is 0. */
3349         param = 0;
3350         /* Pull out a parameter. */
3351         for (i = 0; (params != NULL) && (i < params->n_values); i++) {
3352                 value = g_value_array_get_nth(params, i);
3353                 if (!G_VALUE_HOLDS_LONG(value)) {
3354                         continue;
3355                 }
3356                 param = g_value_get_long(value);
3357         }
3358         /* Clear the right area. */
3359         switch (param) {
3360                 case 0:
3361                         /* Clear to end of the line. */
3362                         vte_sequence_handler_ce(terminal, NULL, 0, NULL);
3363                         break;
3364                 case 1:
3365                         /* Clear to start of the line. */
3366                         vte_sequence_handler_cb(terminal, NULL, 0, NULL);
3367                         break;
3368                 case 2:
3369                         /* Clear the entire line. */
3370                         vte_sequence_handler_clear_current_line(terminal,
3371                                                                 NULL, 0, NULL);
3372                         break;
3373                 default:
3374                         break;
3375         }
3376 }
3377
3378 /* Perform a full-bore reset. */
3379 static void
3380 vte_sequence_handler_full_reset(VteTerminal *terminal,
3381