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