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