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