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