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