don't disable use of deprecated APIs unless asked to do so. add Meta case
[vte.git] / src / vte.c
1 /*
2  * Copyright (C) 2001,2002,2003 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
21 #include "../config.h"
22
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/param.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <math.h>
31 #include <pwd.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #ifdef HAVE_TERMIOS_H
37 #include <termios.h>
38 #endif
39 #include <unistd.h>
40 #ifdef HAVE_WCHAR_H
41 #include <wchar.h>
42 #endif
43 #include <glib.h>
44 #include <glib-object.h>
45 #include <gdk/gdk.h>
46 #include <gdk/gdkkeysyms.h>
47 #include <gtk/gtk.h>
48 #include <pango/pango.h>
49 #include "buffer.h"
50 #include "caps.h"
51 #include "debug.h"
52 #include "iso2022.h"
53 #include "keymap.h"
54 #include "marshal.h"
55 #include "matcher.h"
56 #include "pty.h"
57 #include "reaper.h"
58 #include "ring.h"
59 #include "vte.h"
60 #include "vteaccess.h"
61 #include "vteconv.h"
62 #include "vtedraw.h"
63 #include "vteint.h"
64 #include "vteregex.h"
65 #include "vtetc.h"
66 #include <fontconfig/fontconfig.h>
67
68 #ifdef HAVE_LOCALE_H
69 #include <locale.h>
70 #endif
71
72 #ifndef HAVE_WINT_T
73 typedef gunichar wint_t;
74 #endif
75
76 #ifdef ENABLE_NLS
77 #include <libintl.h>
78 #define _(String) dgettext(PACKAGE, String)
79 #else
80 #define _(String) String
81 #define bindtextdomain(package,dir)
82 #endif
83
84 #define VTE_PAD_WIDTH                   1
85 #define VTE_TAB_WIDTH                   8
86 #define VTE_LINE_WIDTH                  1
87 #define VTE_COLOR_SET_SIZE              8
88 #define VTE_COLOR_PLAIN_OFFSET          0
89 #define VTE_COLOR_BRIGHT_OFFSET         8
90 #define VTE_COLOR_DIM_OFFSET            16
91 #define VTE_DEF_FG                      24
92 #define VTE_DEF_BG                      25
93 #define VTE_BOLD_FG                     26
94 #define VTE_DIM_FG                      27
95 #define VTE_DEF_HL                      28
96 #define VTE_CUR_BG                      29
97 #define VTE_SATURATION_MAX              10000
98 #define VTE_SCROLLBACK_MIN              100
99 #define VTE_DEFAULT_EMULATION           "xterm"
100 #define VTE_DEFAULT_CURSOR              GDK_XTERM
101 #define VTE_MOUSING_CURSOR              GDK_LEFT_PTR
102 #define VTE_TAB_MAX                     999
103 #define VTE_ADJUSTMENT_PRIORITY         G_PRIORITY_DEFAULT_IDLE
104 #define VTE_INPUT_RETRY_PRIORITY        G_PRIORITY_HIGH
105 #define VTE_INPUT_PRIORITY              G_PRIORITY_DEFAULT_IDLE
106 #define VTE_CHILD_INPUT_PRIORITY        G_PRIORITY_DEFAULT_IDLE
107 #define VTE_CHILD_OUTPUT_PRIORITY       G_PRIORITY_HIGH
108 #define VTE_FX_PRIORITY                 G_PRIORITY_DEFAULT_IDLE
109 #define VTE_REGCOMP_FLAGS               REG_EXTENDED
110 #define VTE_REGEXEC_FLAGS               0
111 #define VTE_INPUT_CHUNK_SIZE            0x1000
112 #define VTE_INVALID_SOURCE              -1
113 #define VTE_INVALID_BYTE                '?'
114 #define VTE_COALESCE_TIMEOUT            2
115
116 /* The structure we use to hold characters we're supposed to display -- this
117  * includes any supported visible attributes. */
118 struct vte_charcell {
119         gunichar c;             /* The Unicode character. */
120         guint32 columns: 11;    /* Number of visible columns (as determined
121                                    by g_unicode_iswide(c)).  Use as many bits
122                                    as possible without making this structure
123                                    grow any larger. */
124         guint32 fragment: 1;    /* The nth fragment of a wide character. */
125         guint32 fore: 5;        /* Indices in the color palette for the */
126         guint32 back: 5;        /* foreground and background of the cell. */
127         guint32 standout: 1;    /* Single-bit attributes. */
128         guint32 underline: 1;
129         guint32 strikethrough: 1;
130         guint32 reverse: 1;
131         guint32 blink: 1;
132         guint32 half: 1;
133         guint32 bold: 1;
134         guint32 invisible: 1;
135         guint32 protect: 1;
136         guint32 alternate: 1;
137 };
138
139 /* A match regex, with a tag. */
140 struct vte_match_regex {
141         struct _vte_regex *reg;
142         gint tag;
143         GdkCursor *cursor;
144 };
145
146 /* The terminal's keypad/cursor state.  A terminal can either be using the
147  * normal keypad, or the "application" keypad. */
148 typedef enum _VteKeymode {
149         VTE_KEYMODE_NORMAL,
150         VTE_KEYMODE_APPLICATION
151 } VteKeymode;
152
153 typedef struct _VteScreen VteScreen;
154
155 typedef struct _VteWordCharRange {
156         gunichar start, end;
157 } VteWordCharRange;
158
159 typedef struct _VteRowData {
160         GArray *cells;
161         guchar soft_wrapped: 1;
162 } VteRowData;
163
164 /* Terminal private data. */
165 struct _VteTerminalPrivate {
166         /* Emulation setup data. */
167         struct _vte_termcap *termcap;   /* termcap storage */
168         struct _vte_matcher *matcher;   /* control sequence matcher */
169         const char *termcap_path;       /* path to termcap file */
170         const char *emulation;          /* terminal type to emulate */
171         GTree *sequences;               /* sequence handlers, keyed by GQuark
172                                            based on the sequence name */
173         struct vte_terminal_flags {     /* boolean termcap flags */
174                 gboolean am;
175                 gboolean bw;
176                 gboolean ul;
177                 gboolean xn;
178         } flags;
179         int keypad_mode, cursor_mode;   /* these would be VteKeymodes, but we
180                                            need to guarantee its type */
181         gboolean sun_fkey_mode;
182         gboolean hp_fkey_mode;
183         gboolean legacy_fkey_mode;
184         gboolean vt220_fkey_mode;
185         int fkey;                       /* this would be a VteFKey, but we
186                                            need to guarantee its type */
187         GHashTable *dec_saved;
188         int default_column_count, default_row_count;    /* default sizes */
189
190         /* PTY handling data. */
191         const char *shell;              /* shell we started */
192         int pty_master;                 /* pty master descriptor */
193         GIOChannel *pty_input;          /* master input watch */
194         guint pty_input_source;
195         GIOChannel *pty_output;         /* master output watch */
196         guint pty_output_source;
197         pid_t pty_pid;                  /* pid of child using pty slave */
198         VteReaper *pty_reaper;
199
200         /* Input data queues. */
201         const char *encoding;           /* the pty's encoding */
202         struct _vte_iso2022_state *iso2022;
203         struct _vte_buffer *incoming;   /* pending bytestream */
204         GArray *pending;                /* pending characters */
205         gboolean processing;
206         gint processing_tag;
207
208         /* Output data queue. */
209         struct _vte_buffer *outgoing;   /* pending input characters */
210         VteConv outgoing_conv;
211
212         /* IConv buffer. */
213         struct _vte_buffer *conv_buffer;
214
215         /* Screen data.  We support the normal screen, and an alternate
216          * screen, which seems to be a DEC-specific feature. */
217         struct _VteScreen {
218                 VteRing *row_data;      /* row data, arranged as a GArray of
219                                            vte_charcell structures */
220                 struct vte_cursor_position {
221                         long row, col;
222                 } cursor_current, cursor_saved;
223                                         /* the current and saved positions of
224                                            the [insertion] cursor -- current is
225                                            absolute, saved is relative to the
226                                            insertion delta */
227                 gboolean reverse_mode;  /* reverse mode */
228                 gboolean origin_mode;   /* origin mode */
229                 gboolean sendrecv_mode; /* sendrecv mode */
230                 gboolean insert_mode;   /* insert mode */
231                 gboolean linefeed_mode; /* linefeed mode */
232                 struct vte_scrolling_region {
233                         int start, end;
234                 } scrolling_region;     /* the region we scroll in */
235                 gboolean scrolling_restricted;
236                 long scroll_delta;      /* scroll offset */
237                 long insert_delta;      /* insertion offset */
238                 struct vte_charcell defaults;   /* default characteristics
239                                                    for insertion of any new
240                                                    characters */
241                 struct vte_charcell color_defaults;     /* original defaults
242                                                            plus the current
243                                                            fore/back */
244                 struct vte_charcell fill_defaults;      /* original defaults
245                                                            plus the current
246                                                            fore/back with no
247                                                            character data */
248                 struct vte_charcell basic_defaults;     /* original defaults */
249                 gboolean status_line;
250                 GString *status_line_contents;
251         } normal_screen, alternate_screen, *screen;
252
253         /* Selection information. */
254         GArray *word_chars;
255         gboolean has_selection;
256         gboolean selecting;
257         gboolean selecting_restart;
258         gboolean selecting_had_delta;
259         char *selection;
260         enum vte_selection_type {
261                 selection_type_char,
262                 selection_type_word,
263                 selection_type_line
264         } selection_type;
265         struct selection_event_coords {
266                 double x, y;
267         } selection_origin, selection_last, selection_restart_origin;
268         struct selection_cell_coords {
269                 long x, y;
270         } selection_start, selection_end;
271
272         /* Miscellaneous options. */
273         VteTerminalEraseBinding backspace_binding, delete_binding;
274         gboolean meta_sends_escape;
275         gboolean audible_bell;
276         gboolean visible_bell;
277         gboolean margin_bell;
278         guint bell_margin;
279         gboolean allow_bold;
280         gboolean nrc_mode;
281         gboolean smooth_scroll;
282         GHashTable *tabstops;
283         gboolean text_modified_flag;
284         glong text_inserted_count;
285         glong text_deleted_count;
286
287         /* Scrolling options. */
288         gboolean scroll_background;
289         long scroll_lock_count;
290         gboolean scroll_on_output;
291         gboolean scroll_on_keystroke;
292         long scrollback_lines;
293
294         /* Cursor blinking. */
295         int cursor_force_fg;
296         gboolean cursor_blinks;
297         gint cursor_blink_tag;
298         gint cursor_blink_timeout;
299         gboolean cursor_visible;
300
301         /* Input device options. */
302         time_t last_keypress_time;
303         gboolean mouse_send_xy_on_click;
304         gboolean mouse_send_xy_on_button;
305         gboolean mouse_hilite_tracking;
306         gboolean mouse_cell_motion_tracking;
307         gboolean mouse_all_motion_tracking;
308         guint mouse_last_button;
309         gdouble mouse_last_x, mouse_last_y;
310         gboolean mouse_autohide;
311         guint mouse_autoscroll_tag;
312
313         /* State variables for handling match checks. */
314         char *match_contents;
315         GArray *match_attributes;
316         GArray *match_regexes;
317         int match_previous;
318         struct {
319                 long row, column;
320         } match_start, match_end;
321
322         /* Data used when rendering the text which does not require server
323          * resources and which can be kept after unrealizing. */
324         PangoFontDescription *fontdesc;
325         GtkSettings *connected_settings;
326
327         /* Data used when rendering the text which reflects server resources
328          * and data, which should be dropped when unrealizing and (re)created
329          * when realizing. */
330         struct _vte_draw *draw;
331
332         gboolean palette_initialized;
333         gboolean highlight_color_set;
334         gboolean cursor_color_set;
335         struct vte_palette_entry {
336                 guint16 red, green, blue;
337         } palette[VTE_CUR_BG + 1];
338
339         /* Mouse cursors. */
340         gboolean mouse_cursor_visible;
341         GdkCursor *mouse_default_cursor,
342                   *mouse_mousing_cursor,
343                   *mouse_inviso_cursor;
344
345         /* Input method support. */
346         GtkIMContext *im_context;
347         gboolean im_preedit_active;
348         char *im_preedit;
349         PangoAttrList *im_preedit_attrs;
350         int im_preedit_cursor;
351
352         /* Our accessible peer. */
353         gpointer accessible;
354         gboolean accessible_emit;
355
356         /* Adjustment updates pending. */
357         gboolean adjustment_changed_tag;
358
359         /* Background images/"transparency". */
360         gboolean bg_update_pending;
361         gboolean bg_transparent;
362         GdkPixbuf *bg_pixbuf;
363         char *bg_file;
364         guint bg_update_tag;
365         GdkColor bg_tint_color;
366         long bg_saturation;     /* out of VTE_SATURATION_MAX */
367
368         /* Key modifiers. */
369         GdkModifierType modifiers;
370
371         /* Obscured? state. */
372         GdkVisibilityState visibility_state;
373 };
374
375 /* A function which can handle a terminal control sequence.  Returns TRUE only
376  * if something happened (usually a signal emission) to which the controlling
377  * application must have an immediate opportunity to respond. */
378 typedef gboolean (*VteTerminalSequenceHandler)(VteTerminal *terminal,
379                                                const char *match,
380                                                GQuark match_quark,
381                                                GValueArray *params);
382 static void vte_terminal_set_termcap(VteTerminal *terminal, const char *path,
383                                      gboolean reset);
384 static void vte_terminal_ensure_cursor(VteTerminal *terminal, gboolean current);
385 static void vte_terminal_paste(VteTerminal *terminal, GdkAtom board);
386 static void vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
387                                      gboolean force_insert_mode,
388                                      gboolean invalidate_cells,
389                                      gboolean paint_cells,
390                                      gboolean ensure_after,
391                                      gint forced_width);
392 static gboolean vte_sequence_handler_clear_screen(VteTerminal *terminal,
393                                                   const char *match,
394                                                   GQuark match_quark,
395                                                   GValueArray *params);
396 static gboolean vte_sequence_handler_do(VteTerminal *terminal,
397                                         const char *match,
398                                         GQuark match_quark,
399                                         GValueArray *params);
400 static gboolean vte_sequence_handler_DO(VteTerminal *terminal,
401                                         const char *match,
402                                         GQuark match_quark,
403                                         GValueArray *params);
404 static gboolean vte_sequence_handler_ho(VteTerminal *terminal,
405                                         const char *match,
406                                         GQuark match_quark,
407                                         GValueArray *params);
408 static gboolean vte_sequence_handler_index(VteTerminal *terminal,
409                                            const char *match,
410                                            GQuark match_quark,
411                                            GValueArray *params);
412 static gboolean vte_sequence_handler_le(VteTerminal *terminal,
413                                         const char *match,
414                                         GQuark match_quark,
415                                         GValueArray *params);
416 static gboolean vte_sequence_handler_LE(VteTerminal *terminal,
417                                             const char *match,
418                                             GQuark match_quark,
419                                             GValueArray *params);
420 static gboolean vte_sequence_handler_nd(VteTerminal *terminal,
421                                         const char *match,
422                                         GQuark match_quark,
423                                         GValueArray *params);
424 static gboolean vte_sequence_handler_sf(VteTerminal *terminal,
425                                         const char *match,
426                                         GQuark match_quark,
427                                         GValueArray *params);
428 static gboolean vte_sequence_handler_sr(VteTerminal *terminal,
429                                         const char *match,
430                                         GQuark match_quark,
431                                         GValueArray *params);
432 static gboolean vte_sequence_handler_ue(VteTerminal *terminal,
433                                         const char *match,
434                                         GQuark match_quark,
435                                         GValueArray *params);
436 static gboolean vte_sequence_handler_up(VteTerminal *terminal,
437                                         const char *match,
438                                         GQuark match_quark,
439                                         GValueArray *params);
440 static gboolean vte_sequence_handler_UP(VteTerminal *terminal,
441                                         const char *match,
442                                         GQuark match_quark,
443                                         GValueArray *params);
444 static gboolean vte_sequence_handler_us(VteTerminal *terminal,
445                                         const char *match,
446                                         GQuark match_quark,
447                                         GValueArray *params);
448 static gboolean vte_sequence_handler_vb(VteTerminal *terminal,
449                                         const char *match,
450                                         GQuark match_quark,
451                                         GValueArray *params);
452 static gboolean vte_terminal_io_read(GIOChannel *channel,
453                                      GdkInputCondition condition,
454                                      gpointer data);
455 static gboolean vte_terminal_io_write(GIOChannel *channel,
456                                       GdkInputCondition condition,
457                                       gpointer data);
458 static void vte_terminal_match_hilite_clear(VteTerminal *terminal);
459 static gboolean vte_terminal_background_update(gpointer data);
460 static void vte_terminal_queue_background_update(VteTerminal *terminal);
461 static void vte_terminal_queue_adjustment_changed(VteTerminal *terminal);
462 static gboolean vte_terminal_process_incoming(gpointer data);
463 static char *vte_terminal_get_text_range_maybe_wrapped(VteTerminal *terminal,
464                                                        glong start_row,
465                                                        glong start_col,
466                                                        glong end_row,
467                                                        glong end_col,
468                                                        gboolean wrap,
469                                                        gboolean(*is_selected)(VteTerminal *,
470                                                                               glong,
471                                                                               glong,
472                                                                               gpointer),
473                                                        gpointer data,
474                                                        GArray *attributes);
475 static char *vte_terminal_get_text_maybe_wrapped(VteTerminal *terminal,
476                                                  gboolean wrap,
477                                                  gboolean(*is_selected)(VteTerminal *,
478                                                                         glong,
479                                                                         glong,
480                                                                         gpointer),
481                                                  gpointer data,
482                                                  GArray *attributes);
483 static void _vte_terminal_disconnect_pty_read(VteTerminal *terminal);
484 static void _vte_terminal_disconnect_pty_write(VteTerminal *terminal);
485
486 /* Free a no-longer-used row data array. */
487 static void
488 vte_free_row_data(gpointer freeing, gpointer data)
489 {
490         if (freeing) {
491                 VteRowData *row = (VteRowData*) freeing;
492                 g_array_free(row->cells, TRUE);
493                 g_free(row);
494         }
495 }
496
497 /* Append a single item to a GArray a given number of times. Centralizing all
498  * of the places we do this may let me do something more clever later. */
499 static void
500 vte_g_array_fill(GArray *array, gpointer item, guint final_size)
501 {
502         g_assert(array != NULL);
503         if (array->len >= final_size) {
504                 return;
505         }
506         g_assert(item != NULL);
507
508         while (array->len < final_size) {
509                 g_array_append_vals(array, item, 1);
510         }
511 }
512
513 /* Allocate a new line. */
514 static VteRowData *
515 vte_new_row_data(VteTerminal *terminal)
516 {
517         VteRowData *row = NULL;
518         row = g_malloc0(sizeof(VteRowData));
519         row->cells = g_array_new(FALSE, FALSE, sizeof(struct vte_charcell));
520         row->soft_wrapped = 0;
521         return row;
522 }
523
524 /* Allocate a new line of a given size. */
525 static VteRowData *
526 vte_new_row_data_sized(VteTerminal *terminal, gboolean fill)
527 {
528         VteRowData *row = NULL;
529         row = g_malloc0(sizeof(VteRowData));
530         row->cells = g_array_sized_new(FALSE, FALSE,
531                                        sizeof(struct vte_charcell),
532                                        terminal->column_count);
533         row->soft_wrapped = 0;
534         if (fill) {
535                 vte_g_array_fill(row->cells,
536                                  &terminal->pvt->screen->fill_defaults,
537                                  terminal->column_count);
538         }
539         return row;
540 }
541
542 /* Check how long a string of unichars is.  Slow version. */
543 static gssize
544 vte_unichar_strlen(gunichar *c)
545 {
546         int i;
547         for (i = 0; c[i] != 0; i++) ;
548         return i;
549 }
550
551 /* Reset defaults for character insertion. */
552 static void
553 vte_terminal_set_default_attributes(VteTerminal *terminal)
554 {
555         g_return_if_fail(VTE_IS_TERMINAL(terminal));
556         terminal->pvt->screen->defaults.c = ' ';
557         terminal->pvt->screen->defaults.columns = 1;
558         terminal->pvt->screen->defaults.fragment = 0;
559         terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
560         terminal->pvt->screen->defaults.back = VTE_DEF_BG;
561         terminal->pvt->screen->defaults.reverse = 0;
562         terminal->pvt->screen->defaults.bold = 0;
563         terminal->pvt->screen->defaults.invisible = 0;
564         terminal->pvt->screen->defaults.protect = 0;
565         terminal->pvt->screen->defaults.standout = 0;
566         terminal->pvt->screen->defaults.underline = 0;
567         terminal->pvt->screen->defaults.strikethrough = 0;
568         terminal->pvt->screen->defaults.half = 0;
569         terminal->pvt->screen->defaults.blink = 0;
570         /* Alternate charset isn't an attribute, though we treat it as one.
571          * terminal->pvt->screen->defaults.alternate = 0; */
572         terminal->pvt->screen->basic_defaults = terminal->pvt->screen->defaults;
573         terminal->pvt->screen->color_defaults = terminal->pvt->screen->defaults;
574         terminal->pvt->screen->fill_defaults = terminal->pvt->screen->defaults;
575 }
576
577 /* Cause certain cells to be repainted. */
578 static void
579 vte_invalidate_cells(VteTerminal *terminal,
580                      glong column_start, gint column_count,
581                      glong row_start, gint row_count)
582 {
583         GdkRectangle rect;
584         GtkWidget *widget;
585
586         g_return_if_fail(VTE_IS_TERMINAL(terminal));
587         widget = GTK_WIDGET(terminal);
588         if (!GTK_WIDGET_REALIZED(widget)) {
589                 return;
590         }
591         if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) {
592                 return;
593         }
594
595         /* Subtract the scrolling offset from the row start so that the
596          * resulting rectangle is relative to the visible portion of the
597          * buffer. */
598         row_start -= terminal->pvt->screen->scroll_delta;
599
600         /* Clamp the start values to reasonable numbers. */
601         column_start = (column_start > 0) ? column_start : 0;
602         row_start = (row_start > 0) ? row_start : 0;
603
604         /* Convert the column and row start and end to pixel values
605          * by multiplying by the size of a character cell. */
606         rect.x = column_start * terminal->char_width + VTE_PAD_WIDTH;
607         rect.width = column_count * terminal->char_width;
608         if (column_start == 0) {
609                 /* Include the left border. */
610                 rect.x -= VTE_PAD_WIDTH;
611                 rect.width += VTE_PAD_WIDTH;
612         }
613         if (column_start + column_count == terminal->column_count) {
614                 /* Include the right border. */
615                 rect.width += VTE_PAD_WIDTH;
616         }
617
618         rect.y = row_start * terminal->char_height + VTE_PAD_WIDTH;
619         rect.height = row_count * terminal->char_height;
620         if (rect.y == 0) {
621                 /* Include the top border. */
622                 rect.y -= VTE_PAD_WIDTH;
623                 rect.height += VTE_PAD_WIDTH;
624         }
625         if (row_start + row_count == terminal->row_count) {
626                 /* Include the bottom border. */
627                 rect.height += VTE_PAD_WIDTH;
628         }
629
630         /* Invalidate the rectangle. */
631         gdk_window_invalidate_rect(widget->window, &rect, FALSE);
632 }
633
634 /* Redraw the entire visible portion of the window. */
635 static void
636 vte_invalidate_all(VteTerminal *terminal)
637 {
638         GdkRectangle rect;
639         GtkWidget *widget;
640         int width, height;
641
642         g_return_if_fail(VTE_IS_TERMINAL(terminal));
643         if (!GTK_IS_WIDGET(terminal)) {
644                return;
645         }
646         widget = GTK_WIDGET(terminal);
647         if (!GTK_WIDGET_REALIZED(widget)) {
648                 return;
649         }
650         if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) {
651                 return;
652         }
653
654         /* Expose the entire widget area. */
655         width = height = 0;
656         gdk_drawable_get_size(widget->window, &width, &height);
657         rect.x = 0;
658         rect.y = 0;
659         rect.width = width;
660         rect.height = height;
661         gdk_window_invalidate_rect(widget->window, &rect, FALSE);
662 }
663
664 /* Scroll a rectangular region up or down by a fixed number of lines. */
665 static void
666 vte_terminal_scroll_region(VteTerminal *terminal,
667                            long row, glong count, glong delta)
668 {
669         gboolean repaint = TRUE;
670         glong height;
671
672         if ((delta == 0) || (count == 0)) {
673                 /* Shenanigans! */
674                 return;
675         }
676
677         /* We only do this if we're scrolling the entire window. */
678         if (!terminal->pvt->bg_transparent &&
679             (terminal->pvt->bg_pixbuf == NULL) &&
680             (terminal->pvt->bg_file == NULL) &&
681             (row == terminal->pvt->screen->scroll_delta) &&
682             (count == terminal->row_count) &&
683             (terminal->pvt->scroll_lock_count == 0)) {
684                 height = terminal->char_height;
685                 gdk_window_scroll((GTK_WIDGET(terminal))->window,
686                                   0, delta * height);
687                 if (delta > 0) {
688                         vte_invalidate_cells(terminal,
689                                              0, terminal->column_count,
690                                              0, delta);
691                 } else {
692                         vte_invalidate_cells(terminal,
693                                              0, terminal->column_count,
694                                              terminal->row_count + delta,
695                                              -delta);
696                 }
697                 repaint = FALSE;
698         }
699
700         if (repaint) {
701                 if (terminal->pvt->scroll_background) {
702                         /* We have to repaint the entire window. */
703                         vte_invalidate_all(terminal);
704                 } else {
705                         /* We have to repaint the area which is to be
706                          * scrolled. */
707                         vte_invalidate_cells(terminal,
708                                              0, terminal->column_count,
709                                              row, count);
710                 }
711         }
712 }
713
714 /* Find the character an the given position in the backscroll buffer. */
715 static struct vte_charcell *
716 vte_terminal_find_charcell(VteTerminal *terminal, glong col, glong row)
717 {
718         VteRowData *rowdata;
719         struct vte_charcell *ret = NULL;
720         VteScreen *screen;
721         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
722         screen = terminal->pvt->screen;
723         if (_vte_ring_contains(screen->row_data, row)) {
724                 rowdata = _vte_ring_index(screen->row_data, VteRowData *, row);
725                 if (rowdata->cells->len > col) {
726                         ret = &g_array_index(rowdata->cells,
727                                              struct vte_charcell,
728                                              col);
729                 }
730         }
731         return ret;
732 }
733
734 /* Determine the width of the portion of the preedit string which lies
735  * to the left of the cursor, or the entire string, in columns. */
736 static gssize
737 vte_terminal_preedit_width(VteTerminal *terminal, gboolean left_only)
738 {
739         gunichar c;
740         int i;
741         gssize ret = 0;
742         const char *preedit = NULL;
743
744         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), 0);
745
746         if (terminal->pvt->im_preedit != NULL) {
747                 preedit = terminal->pvt->im_preedit;
748                 for (i = 0;
749                      (preedit != NULL) &&
750                      (preedit[0] != '\0') &&
751                      (!left_only || (i < terminal->pvt->im_preedit_cursor));
752                      i++) {
753                         c = g_utf8_get_char(preedit);
754                         ret += _vte_iso2022_unichar_width(c);
755                         preedit = g_utf8_next_char(preedit);
756                 }
757         }
758
759         return ret;
760 }
761
762 /* Determine the length of the portion of the preedit string which lies
763  * to the left of the cursor, or the entire string, in gunichars. */
764 static gssize
765 vte_terminal_preedit_length(VteTerminal *terminal, gboolean left_only)
766 {
767         gunichar c;
768         int i = 0;
769         const char *preedit = NULL;
770
771         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), 0);
772
773         if (terminal->pvt->im_preedit != NULL) {
774                 preedit = terminal->pvt->im_preedit;
775                 for (i = 0;
776                      (preedit != NULL) &&
777                      (preedit[0] != '\0') &&
778                      (!left_only || (i < terminal->pvt->im_preedit_cursor));
779                      i++) {
780                         c = g_utf8_get_char(preedit);
781                         preedit = g_utf8_next_char(preedit);
782                 }
783         }
784
785         return i;
786 }
787
788 /* Cause the cursor to be redrawn. */
789 static void
790 vte_invalidate_cursor_once(gpointer data, gboolean periodic)
791 {
792         VteTerminal *terminal;
793         VteScreen *screen;
794         struct vte_charcell *cell;
795         gssize preedit_width;
796         int column, columns, row;
797
798         if (!VTE_IS_TERMINAL(data)) {
799                 return;
800         }
801
802         terminal = VTE_TERMINAL(data);
803
804         if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) {
805                 return;
806         }
807
808         if (periodic) {
809                 if (!terminal->pvt->cursor_blinks) {
810                         return;
811                 }
812         }
813
814         if (terminal->pvt->cursor_visible &&
815             GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
816                 preedit_width = vte_terminal_preedit_width(terminal, FALSE);
817
818                 screen = terminal->pvt->screen;
819                 row = screen->cursor_current.row;
820                 column = screen->cursor_current.col;
821                 columns = 1;
822                 cell = vte_terminal_find_charcell(terminal,
823                                                   column,
824                                                   screen->cursor_current.row);
825                 while ((cell != NULL) && (cell->fragment) && (column > 0)) {
826                         column--;
827                         cell = vte_terminal_find_charcell(terminal,
828                                                           column,
829                                                           row);
830                 }
831                 if (cell != NULL) {
832                         columns = cell->columns;
833                         if (_vte_draw_get_char_width(terminal->pvt->draw,
834                                                      cell->c,
835                                                      cell->columns) >
836                             terminal->char_width * columns) {
837                                 columns++;
838                         }
839                 }
840                 if (preedit_width > 0) {
841                         columns += preedit_width;
842                         columns++; /* one more for the preedit cursor */
843                 }
844                 if (column + columns > terminal->column_count) {
845                         column = MAX(0, terminal->column_count - columns);
846                 }
847
848                 vte_invalidate_cells(terminal,
849                                      column, columns,
850                                      row, 1);
851 #ifdef VTE_DEBUG
852                 if (_vte_debug_on(VTE_DEBUG_UPDATES)) {
853                         fprintf(stderr, "Invalidating cursor at (%ld,%d-%d)."
854                                 "\n", screen->cursor_current.row,
855                                 column,
856                                 column + columns);
857                 }
858 #endif
859         }
860 }
861
862 /* Invalidate the cursor repeatedly. */
863 static gboolean
864 vte_invalidate_cursor_periodic(gpointer data)
865 {
866         VteTerminal *terminal;
867         GtkWidget *widget;
868         GtkSettings *settings;
869         gint blink_cycle = 1000;
870
871         g_return_val_if_fail(VTE_IS_TERMINAL(data), FALSE);
872         widget = GTK_WIDGET(data);
873         if (!GTK_WIDGET_REALIZED(widget)) {
874                 return TRUE;
875         }
876         if (!GTK_WIDGET_HAS_FOCUS(widget)) {
877                 return TRUE;
878         }
879
880         terminal = VTE_TERMINAL(widget);
881         if (terminal->pvt->cursor_blinks) {
882                 vte_invalidate_cursor_once(terminal, TRUE);
883         }
884
885         settings = gtk_widget_get_settings(GTK_WIDGET(data));
886         if (G_IS_OBJECT(settings)) {
887                 g_object_get(G_OBJECT(settings), "gtk-cursor-blink-time",
888                              &blink_cycle, NULL);
889         }
890
891         if (terminal->pvt->cursor_blink_timeout != blink_cycle) {
892                 terminal->pvt->cursor_blink_tag = g_timeout_add_full(G_PRIORITY_LOW,
893                                                                      blink_cycle / 2,
894                                                                      vte_invalidate_cursor_periodic,
895                                                                      terminal,
896                                                                      NULL);
897                 terminal->pvt->cursor_blink_timeout = blink_cycle;
898                 return FALSE;
899         } else {
900                 return TRUE;
901         }
902 }
903
904 /* Emit a "selection_changed" signal. */
905 static void
906 vte_terminal_emit_selection_changed(VteTerminal *terminal)
907 {
908 #ifdef VTE_DEBUG
909         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
910                 fprintf(stderr, "Emitting `selection-changed'.\n");
911         }
912 #endif
913         g_signal_emit_by_name(terminal, "selection-changed");
914 }
915
916 /* Emit a "commit" signal. */
917 static void
918 vte_terminal_emit_commit(VteTerminal *terminal, gchar *text, guint length)
919 {
920         char *wrapped = NULL;
921 #ifdef VTE_DEBUG
922         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
923                 fprintf(stderr, "Emitting `commit' of %d bytes.\n", length);
924         }
925 #endif
926         if (length == -1) {
927                 length = strlen(text);
928                 wrapped = text;
929         } else {
930                 wrapped = g_malloc0(length + 1);
931                 memcpy(wrapped, text, length);
932         }
933         g_signal_emit_by_name(terminal, "commit", wrapped, length);
934         if (wrapped != text) {
935                 g_free(wrapped);
936         }
937 }
938
939 /* Emit an "emulation-changed" signal. */
940 static void
941 vte_terminal_emit_emulation_changed(VteTerminal *terminal)
942 {
943 #ifdef VTE_DEBUG
944         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
945                 fprintf(stderr, "Emitting `emulation-changed'.\n");
946         }
947 #endif
948         g_signal_emit_by_name(terminal, "emulation-changed");
949 }
950
951 /* Emit an "encoding-changed" signal. */
952 static void
953 vte_terminal_emit_encoding_changed(VteTerminal *terminal)
954 {
955 #ifdef VTE_DEBUG
956         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
957                 fprintf(stderr, "Emitting `encoding-changed'.\n");
958         }
959 #endif
960         g_signal_emit_by_name(terminal, "encoding-changed");
961 }
962
963 /* Emit a "child-exited" signal. */
964 static void
965 vte_terminal_emit_child_exited(VteTerminal *terminal)
966 {
967 #ifdef VTE_DEBUG
968         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
969                 fprintf(stderr, "Emitting `child-exited'.\n");
970         }
971 #endif
972         g_signal_emit_by_name(terminal, "child-exited");
973 }
974
975 /* Emit a "contents_changed" signal. */
976 static void
977 vte_terminal_emit_contents_changed(VteTerminal *terminal)
978 {
979 #ifdef VTE_DEBUG
980         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
981                 fprintf(stderr, "Emitting `contents-changed'.\n");
982         }
983 #endif
984         g_signal_emit_by_name(terminal, "contents-changed");
985 }
986
987 /* Emit a "cursor_moved" signal. */
988 static void
989 vte_terminal_emit_cursor_moved(VteTerminal *terminal)
990 {
991 #ifdef VTE_DEBUG
992         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
993                 fprintf(stderr, "Emitting `cursor-moved'.\n");
994         }
995 #endif
996         g_signal_emit_by_name(terminal, "cursor-moved");
997 }
998
999 /* Emit an "icon-title-changed" signal. */
1000 static void
1001 vte_terminal_emit_icon_title_changed(VteTerminal *terminal)
1002 {
1003 #ifdef VTE_DEBUG
1004         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1005                 fprintf(stderr, "Emitting `icon-title-changed'.\n");
1006         }
1007 #endif
1008         g_signal_emit_by_name(terminal, "icon-title-changed");
1009 }
1010
1011 /* Emit a "window-title-changed" signal. */
1012 static void
1013 vte_terminal_emit_window_title_changed(VteTerminal *terminal)
1014 {
1015 #ifdef VTE_DEBUG
1016         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1017                 fprintf(stderr, "Emitting `window-title-changed'.\n");
1018         }
1019 #endif
1020         g_signal_emit_by_name(terminal, "window-title-changed");
1021 }
1022
1023 /* Emit a "deiconify-window" signal. */
1024 static void
1025 vte_terminal_emit_deiconify_window(VteTerminal *terminal)
1026 {
1027 #ifdef VTE_DEBUG
1028         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1029                 fprintf(stderr, "Emitting `deiconify-window'.\n");
1030         }
1031 #endif
1032         g_signal_emit_by_name(terminal, "deiconify-window");
1033 }
1034
1035 /* Emit a "iconify-window" signal. */
1036 static void
1037 vte_terminal_emit_iconify_window(VteTerminal *terminal)
1038 {
1039 #ifdef VTE_DEBUG
1040         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1041                 fprintf(stderr, "Emitting `iconify-window'.\n");
1042         }
1043 #endif
1044         g_signal_emit_by_name(terminal, "iconify-window");
1045 }
1046
1047 /* Emit a "raise-window" signal. */
1048 static void
1049 vte_terminal_emit_raise_window(VteTerminal *terminal)
1050 {
1051 #ifdef VTE_DEBUG
1052         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1053                 fprintf(stderr, "Emitting `raise-window'.\n");
1054         }
1055 #endif
1056         g_signal_emit_by_name(terminal, "raise-window");
1057 }
1058
1059 /* Emit a "lower-window" signal. */
1060 static void
1061 vte_terminal_emit_lower_window(VteTerminal *terminal)
1062 {
1063 #ifdef VTE_DEBUG
1064         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1065                 fprintf(stderr, "Emitting `lower-window'.\n");
1066         }
1067 #endif
1068         g_signal_emit_by_name(terminal, "lower-window");
1069 }
1070
1071 /* Emit a "maximize-window" signal. */
1072 static void
1073 vte_terminal_emit_maximize_window(VteTerminal *terminal)
1074 {
1075 #ifdef VTE_DEBUG
1076         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1077                 fprintf(stderr, "Emitting `maximize-window'.\n");
1078         }
1079 #endif
1080         g_signal_emit_by_name(terminal, "maximize-window");
1081 }
1082
1083 /* Emit a "refresh-window" signal. */
1084 static void
1085 vte_terminal_emit_refresh_window(VteTerminal *terminal)
1086 {
1087 #ifdef VTE_DEBUG
1088         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1089                 fprintf(stderr, "Emitting `refresh-window'.\n");
1090         }
1091 #endif
1092         g_signal_emit_by_name(terminal, "refresh-window");
1093 }
1094
1095 /* Emit a "restore-window" signal. */
1096 static void
1097 vte_terminal_emit_restore_window(VteTerminal *terminal)
1098 {
1099 #ifdef VTE_DEBUG
1100         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1101                 fprintf(stderr, "Emitting `restore-window'.\n");
1102         }
1103 #endif
1104         g_signal_emit_by_name(terminal, "restore-window");
1105 }
1106
1107 /* Emit a "eof" signal. */
1108 static void
1109 vte_terminal_emit_eof(VteTerminal *terminal)
1110 {
1111 #ifdef VTE_DEBUG
1112         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1113                 fprintf(stderr, "Emitting `eof'.\n");
1114         }
1115 #endif
1116         g_signal_emit_by_name(terminal, "eof");
1117 }
1118
1119 /* Emit a "char-size-changed" signal. */
1120 static void
1121 vte_terminal_emit_char_size_changed(VteTerminal *terminal,
1122                                     guint width, guint height)
1123 {
1124 #ifdef VTE_DEBUG
1125         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1126                 fprintf(stderr, "Emitting `char-size-changed'.\n");
1127         }
1128 #endif
1129         g_signal_emit_by_name(terminal, "char-size-changed",
1130                               width, height);
1131 }
1132
1133 /* Emit a "resize-window" signal.  (Pixels.) */
1134 static void
1135 vte_terminal_emit_resize_window(VteTerminal *terminal,
1136                                 guint width, guint height)
1137 {
1138 #ifdef VTE_DEBUG
1139         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1140                 fprintf(stderr, "Emitting `resize-window'.\n");
1141         }
1142 #endif
1143         g_signal_emit_by_name(terminal, "resize-window", width, height);
1144 }
1145
1146 /* Emit a "move-window" signal.  (Pixels.) */
1147 static void
1148 vte_terminal_emit_move_window(VteTerminal *terminal, guint x, guint y)
1149 {
1150 #ifdef VTE_DEBUG
1151         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1152                 fprintf(stderr, "Emitting `move-window'.\n");
1153         }
1154 #endif
1155         g_signal_emit_by_name(terminal, "move-window", x, y);
1156 }
1157
1158 /* Emit a "status-line-changed" signal. */
1159 static void
1160 vte_terminal_emit_status_line_changed(VteTerminal *terminal)
1161 {
1162 #ifdef VTE_DEBUG
1163         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1164                 fprintf(stderr, "Emitting `status-line-changed'.\n");
1165         }
1166 #endif
1167         g_signal_emit_by_name(terminal, "status-line-changed");
1168 }
1169
1170 /* Emit an "increase-font-size" signal. */
1171 static void
1172 vte_terminal_emit_increase_font_size(VteTerminal *terminal)
1173 {
1174 #ifdef VTE_DEBUG
1175         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1176                 fprintf(stderr, "Emitting `increase-font-size'.\n");
1177         }
1178 #endif
1179         g_signal_emit_by_name(terminal, "increase-font-size");
1180 }
1181
1182 /* Emit a "decrease-font-size" signal. */
1183 static void
1184 vte_terminal_emit_decrease_font_size(VteTerminal *terminal)
1185 {
1186 #ifdef VTE_DEBUG
1187         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1188                 fprintf(stderr, "Emitting `decrease-font-size'.\n");
1189         }
1190 #endif
1191         g_signal_emit_by_name(terminal, "decrease-font-size");
1192 }
1193
1194 /* Emit a "text-inserted" signal. */
1195 static void
1196 vte_terminal_emit_text_inserted(VteTerminal *terminal)
1197 {
1198         if (!terminal->pvt->accessible_emit) {
1199                 return;
1200         }
1201 #ifdef VTE_DEBUG
1202         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1203                 fprintf(stderr, "Emitting `text-inserted'.\n");
1204         }
1205 #endif
1206         g_signal_emit_by_name(terminal, "text-inserted");
1207 }
1208
1209 /* Emit a "text-deleted" signal. */
1210 static void
1211 vte_terminal_emit_text_deleted(VteTerminal *terminal)
1212 {
1213         if (!terminal->pvt->accessible_emit) {
1214                 return;
1215         }
1216 #ifdef VTE_DEBUG
1217         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1218                 fprintf(stderr, "Emitting `text-deleted'.\n");
1219         }
1220 #endif
1221         g_signal_emit_by_name(terminal, "text-deleted");
1222 }
1223
1224 /* Emit a "text-modified" signal. */
1225 static void
1226 vte_terminal_emit_text_modified(VteTerminal *terminal)
1227 {
1228         if (!terminal->pvt->accessible_emit) {
1229                 return;
1230         }
1231 #ifdef VTE_DEBUG
1232         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1233                 fprintf(stderr, "Emitting `text-modified'.\n");
1234         }
1235 #endif
1236         g_signal_emit_by_name(terminal, "text-modified");
1237 }
1238
1239 /* Emit a "text-scrolled" signal. */
1240 static void
1241 vte_terminal_emit_text_scrolled(VteTerminal *terminal, gint delta)
1242 {
1243         if (!terminal->pvt->accessible_emit) {
1244                 return;
1245         }
1246 #ifdef VTE_DEBUG
1247         if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1248                 fprintf(stderr, "Emitting `text-scrolled'(%d).\n", delta);
1249         }
1250 #endif
1251         g_signal_emit_by_name(terminal, "text-scrolled", delta);
1252 }
1253
1254 /* Deselect anything which is selected and refresh the screen if needed. */
1255 static void
1256 vte_terminal_deselect_all(VteTerminal *terminal)
1257 {
1258         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1259         if (terminal->pvt->has_selection) {
1260                 terminal->pvt->has_selection = FALSE;
1261 #ifdef VTE_DEBUG
1262                 if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
1263                         fprintf(stderr, "Deselecting all text.\n");
1264                 }
1265 #endif
1266                 vte_terminal_emit_selection_changed(terminal);
1267                 vte_invalidate_all(terminal);
1268         }
1269 }
1270
1271 /* Reset the set of tab stops to the default. */
1272 static void
1273 vte_terminal_set_tabstop(VteTerminal *terminal, int column)
1274 {
1275         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1276         if (terminal->pvt->tabstops != NULL) {
1277                 /* Just set a non-NULL pointer for this column number. */
1278                 g_hash_table_insert(terminal->pvt->tabstops,
1279                                     GINT_TO_POINTER(2 * column + 1),
1280                                     terminal);
1281         }
1282 }
1283
1284 /* Remove a tabstop. */
1285 static void
1286 vte_terminal_clear_tabstop(VteTerminal *terminal, int column)
1287 {
1288         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1289         if (terminal->pvt->tabstops != NULL) {
1290                 /* Remove a tab stop from the hash table. */
1291                 g_hash_table_remove(terminal->pvt->tabstops,
1292                                     GINT_TO_POINTER(2 * column + 1));
1293         }
1294 }
1295
1296 /* Check if we have a tabstop at a given position. */
1297 static gboolean
1298 vte_terminal_get_tabstop(VteTerminal *terminal, int column)
1299 {
1300         gpointer hash;
1301         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
1302         if (terminal->pvt->tabstops != NULL) {
1303                 hash = g_hash_table_lookup(terminal->pvt->tabstops,
1304                                            GINT_TO_POINTER(2 * column + 1));
1305                 return (hash != NULL);
1306         } else {
1307                 return FALSE;
1308         }
1309 }
1310
1311 /* Reset the set of tab stops to the default. */
1312 static void
1313 vte_terminal_set_default_tabstops(VteTerminal *terminal)
1314 {
1315         int i, width;
1316         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1317         if (terminal->pvt->tabstops != NULL) {
1318                 g_hash_table_destroy(terminal->pvt->tabstops);
1319         }
1320         terminal->pvt->tabstops = g_hash_table_new(g_direct_hash,
1321                                                    g_direct_equal);
1322         width = _vte_termcap_find_numeric(terminal->pvt->termcap,
1323                                           terminal->pvt->emulation,
1324                                           "it");
1325         if (width == 0) {
1326                 width = VTE_TAB_WIDTH;
1327         }
1328         for (i = 0; i <= VTE_TAB_MAX; i += width) {
1329                 vte_terminal_set_tabstop(terminal, i);
1330         }
1331 }
1332
1333 /* Clear the cache of the screen contents we keep. */
1334 static void
1335 vte_terminal_match_contents_clear(VteTerminal *terminal)
1336 {
1337         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1338         if (terminal->pvt->match_contents != NULL) {
1339                 g_free(terminal->pvt->match_contents);
1340                 terminal->pvt->match_contents = NULL;;
1341         }
1342         if (terminal->pvt->match_attributes != NULL) {
1343                 g_array_free(terminal->pvt->match_attributes, TRUE);
1344                 terminal->pvt->match_attributes = NULL;
1345         }
1346         vte_terminal_match_hilite_clear(terminal);
1347 }
1348
1349 /* Refresh the cache of the screen contents we keep. */
1350 static gboolean
1351 always_selected(VteTerminal *terminal, glong row, glong column, gpointer data)
1352 {
1353         return TRUE;
1354 }
1355 static void
1356 vte_terminal_match_contents_refresh(VteTerminal *terminal)
1357 {
1358         GArray *array;
1359         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1360         vte_terminal_match_contents_clear(terminal);
1361         array = g_array_new(FALSE, TRUE, sizeof(struct _VteCharAttributes));
1362         terminal->pvt->match_contents = vte_terminal_get_text(terminal,
1363                                                               always_selected,
1364                                                               NULL,
1365                                                               array);
1366         terminal->pvt->match_attributes = array;
1367 }
1368
1369 /**
1370  * vte_terminal_match_clear_all:
1371  * @terminal: a #VteTerminal
1372  *
1373  * Clears the list of regular expressions the terminal uses to highlight text
1374  * when the user moves the mouse cursor.
1375  *
1376  */
1377 void
1378 vte_terminal_match_clear_all(VteTerminal *terminal)
1379 {
1380         struct vte_match_regex *regex;
1381         int i;
1382         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1383         for (i = 0; i < terminal->pvt->match_regexes->len; i++) {
1384                 regex = &g_array_index(terminal->pvt->match_regexes,
1385                                        struct vte_match_regex,
1386                                        i);
1387                 /* Unless this is a hole, clean it up. */
1388                 if (regex->tag >= 0) {
1389                         if (regex->cursor != NULL) {
1390                                 gdk_cursor_unref(regex->cursor);
1391                                 regex->cursor = NULL;
1392                         }
1393                         _vte_regex_free(regex->reg);
1394                         regex->reg = NULL;
1395                         regex->tag = -1;
1396                 }
1397         }
1398         g_array_set_size(terminal->pvt->match_regexes, 0);
1399         vte_terminal_match_hilite_clear(terminal);
1400 }
1401
1402 /**
1403  * vte_terminal_match_remove:
1404  * @terminal: a #VteTerminal
1405  * @tag: the tag of the regex to remove
1406  *
1407  * Removes the regular expression which is associated with the given @tag from
1408  * the list of expressions which the terminal will highlight when the user
1409  * moves the mouse cursor over matching text.
1410  *
1411  */
1412 void
1413 vte_terminal_match_remove(VteTerminal *terminal, int tag)
1414 {
1415         struct vte_match_regex *regex;
1416         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1417         if (terminal->pvt->match_regexes->len > tag) {
1418                 /* The tag is an index, so find the corresponding struct. */
1419                 regex = &g_array_index(terminal->pvt->match_regexes,
1420                                        struct vte_match_regex,
1421                                        tag);
1422                 /* If it's already been removed, return. */
1423                 if (regex->tag < 0) {
1424                         return;
1425                 }
1426                 /* Remove this item and leave a hole in its place. */
1427                 if (regex->cursor != NULL) {
1428                         gdk_cursor_unref(regex->cursor);
1429                         regex->cursor = NULL;
1430                 }
1431                 _vte_regex_free(regex->reg);
1432                 regex->reg = NULL;
1433                 regex->tag = -1;
1434         }
1435         vte_terminal_match_hilite_clear(terminal);
1436 }
1437
1438 static GdkCursor *
1439 vte_terminal_cursor_new(VteTerminal *terminal, GdkCursorType cursor_type)
1440 {
1441 #if GTK_CHECK_VERSION(2,2,0)
1442         GdkDisplay *display;
1443         GdkCursor *cursor;
1444
1445         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1446
1447         display = gtk_widget_get_display(GTK_WIDGET(terminal));
1448         cursor = gdk_cursor_new_for_display(display, cursor_type);
1449 #else
1450         GdkCursor *cursor;
1451
1452         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1453
1454         cursor = gdk_cursor_new(cursor_type);
1455 #endif
1456         return cursor;
1457 }
1458
1459 /**
1460  * vte_terminal_match_add:
1461  * @terminal: a #VteTerminal
1462  * @match: a regular expression
1463  *
1464  * Adds a regular expression to the list of matching expressions.  When the
1465  * user moves the mouse cursor over a section of displayed text which matches
1466  * this expression, the text will be highlighted.
1467  *
1468  * Returns: an integer associated with this expression
1469  */
1470 int
1471 vte_terminal_match_add(VteTerminal *terminal, const char *match)
1472 {
1473         struct vte_match_regex new_regex, *regex;
1474         int ret;
1475         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
1476         g_return_val_if_fail(match != NULL, -1);
1477         g_return_val_if_fail(strlen(match) > 0, -1);
1478         memset(&new_regex, 0, sizeof(new_regex));
1479         new_regex.reg = _vte_regex_compile(match);
1480         if (new_regex.reg == NULL) {
1481                 g_warning(_("Error compiling regular expression \"%s\"."),
1482                           match);
1483                 return -1;
1484         }
1485
1486         /* Search for a hole. */
1487         for (ret = 0; ret < terminal->pvt->match_regexes->len; ret++) {
1488                 regex = &g_array_index(terminal->pvt->match_regexes,
1489                                        struct vte_match_regex,
1490                                        ret);
1491                 if (regex->tag == -1) {
1492                         break;
1493                 }
1494         }
1495         /* Set the tag to the insertion point. */
1496         new_regex.tag = ret;
1497         new_regex.cursor = vte_terminal_cursor_new(terminal,
1498                                                    VTE_DEFAULT_CURSOR);
1499         if (ret < terminal->pvt->match_regexes->len) {
1500                 /* Overwrite. */
1501                 g_array_index(terminal->pvt->match_regexes,
1502                               struct vte_match_regex,
1503                               ret) = new_regex;
1504         } else {
1505                 /* Append. */
1506                 g_array_append_val(terminal->pvt->match_regexes, new_regex);
1507         }
1508         return new_regex.tag;
1509 }
1510
1511 /**
1512  * vte_terminal_match_set_cursor:
1513  * @terminal: a #VteTerminal
1514  * @tag: the tag of the regex which should use the specified cursor
1515  * @cursor: the cursor which the terminal should use when the pattern is
1516  * highlighted
1517  *
1518  * Sets which cursor the terminal will use if the pointer is over the pattern
1519  * specified by @tag.  The terminal keeps a reference to @cursor.
1520  *
1521  * Since: 0.11
1522  *
1523  */
1524 void
1525 vte_terminal_match_set_cursor(VteTerminal *terminal, int tag, GdkCursor *cursor)
1526 {
1527         struct vte_match_regex *regex;
1528         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1529         g_return_if_fail(tag < terminal->pvt->match_regexes->len);
1530         regex = &g_array_index(terminal->pvt->match_regexes,
1531                                struct vte_match_regex,
1532                                tag);
1533         if (regex->cursor != NULL) {
1534                 gdk_cursor_unref(regex->cursor);
1535         }
1536         regex->cursor = gdk_cursor_ref(cursor);
1537         vte_terminal_match_hilite_clear(terminal);
1538 }
1539
1540 /**
1541  * vte_terminal_match_set_cursor:
1542  * @terminal: a #VteTerminal
1543  * @tag: the tag of the regex which should use the specified cursor
1544  * @cursor: a #GdkCursorType
1545  *
1546  * Sets which cursor the terminal will use if the pointer is over the pattern
1547  * specified by @tag.  A convenience wrapper for
1548  * vte_terminal_match_set_cursor().
1549  *
1550  * Since: 0.11.9
1551  *
1552  */
1553 void
1554 vte_terminal_match_set_cursor_type(VteTerminal *terminal,
1555                                    int tag, GdkCursorType cursor_type)
1556 {
1557         GdkCursor *cursor;
1558         cursor = vte_terminal_cursor_new(terminal, cursor_type);
1559         vte_terminal_match_set_cursor(terminal, tag, cursor);
1560         gdk_cursor_unref(cursor);
1561 }
1562
1563 /* Check if a given cell on the screen contains part of a matched string.  If
1564  * it does, return the string, and store the match tag in the optional tag
1565  * argument. */
1566 static char *
1567 vte_terminal_match_check_internal(VteTerminal *terminal,
1568                                   long column, glong row,
1569                                   int *tag, int *start, int *end)
1570 {
1571         int i, j, ret, offset;
1572         struct vte_match_regex *regex = NULL;
1573         struct _VteCharAttributes *attr = NULL;
1574         gssize coffset;
1575         struct _vte_regex_match matches[256];
1576 #ifdef VTE_DEBUG
1577         if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1578                 fprintf(stderr, "Checking for match at (%ld,%ld).\n",
1579                         row, column);
1580         }
1581 #endif
1582         if (tag != NULL) {
1583                 *tag = -1;
1584         }
1585         if (start != NULL) {
1586                 *start = 0;
1587         }
1588         if (end != NULL) {
1589                 *end = 0;
1590         }
1591         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1592         if (terminal->pvt->match_contents == NULL) {
1593                 vte_terminal_match_contents_refresh(terminal);
1594         }
1595         /* Map the pointer position to a portion of the string. */
1596         for (offset = terminal->pvt->match_attributes->len - 1;
1597              offset >= 0;
1598              offset--) {
1599                 attr = &g_array_index(terminal->pvt->match_attributes,
1600                                       struct _VteCharAttributes,
1601                                       offset);
1602                 if ((row == attr->row) &&
1603                     (column == attr->column) &&
1604                     (terminal->pvt->match_contents[offset] != ' ')) {
1605                         break;
1606                 }
1607         }
1608 #ifdef VTE_DEBUG
1609         if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1610                 if (offset < 0) {
1611                         fprintf(stderr, "Cursor is not on a character.\n");
1612                 } else {
1613                         fprintf(stderr, "Cursor is on character %d.\n", offset);
1614                 }
1615         }
1616 #endif
1617
1618         /* If the pointer isn't on a matchable character, bug out. */
1619         if (offset < 0) {
1620                 terminal->pvt->match_previous = -1;
1621                 return NULL;
1622         }
1623
1624         /* If the pointer is on a newline, bug out. */
1625         if ((g_ascii_isspace(terminal->pvt->match_contents[offset])) ||
1626             (terminal->pvt->match_contents[offset] == '\0')) {
1627 #ifdef VTE_DEBUG
1628                 if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1629                         fprintf(stderr, "Cursor is on whitespace.\n");
1630                 }
1631 #endif
1632                 terminal->pvt->match_previous = -1;
1633                 return NULL;
1634         }
1635
1636         /* Now iterate over each regex we need to match against. */
1637         for (i = 0; i < terminal->pvt->match_regexes->len; i++) {
1638                 regex = &g_array_index(terminal->pvt->match_regexes,
1639                                        struct vte_match_regex,
1640                                        i);
1641                 /* Skip holes. */
1642                 if (regex->tag < 0) {
1643                         continue;
1644                 }
1645                 /* We'll only match the first item in the buffer which
1646                  * matches, so we'll have to skip each match until we
1647                  * stop getting matches. */
1648                 coffset = 0;
1649                 ret = _vte_regex_exec(regex->reg,
1650                                       terminal->pvt->match_contents + coffset,
1651                                       G_N_ELEMENTS(matches),
1652                                       matches);
1653                 while (ret == 0) {
1654                         for (j = 0;
1655                              (j < G_N_ELEMENTS(matches)) &&
1656                              (matches[j].rm_so != -1);
1657                              j++) {
1658                                 /* The offsets should be "sane". */
1659                                 g_assert(matches[j].rm_so + coffset <
1660                                          terminal->pvt->match_attributes->len);
1661                                 g_assert(matches[j].rm_eo + coffset <=
1662                                          terminal->pvt->match_attributes->len);
1663 #ifdef VTE_DEBUG
1664                                 if (_vte_debug_on(VTE_DEBUG_MISC)) {
1665                                         char *match;
1666                                         struct _VteCharAttributes *sattr, *eattr;
1667                                         match = g_strndup(terminal->pvt->match_contents + matches[j].rm_so + coffset,
1668                                                           matches[j].rm_eo - matches[j].rm_so);
1669                                         sattr = &g_array_index(terminal->pvt->match_attributes,
1670                                                                struct _VteCharAttributes,
1671                                                                matches[j].rm_so + coffset);
1672                                         eattr = &g_array_index(terminal->pvt->match_attributes,
1673                                                                struct _VteCharAttributes,
1674                                                                matches[j].rm_eo + coffset - 1);
1675                                         fprintf(stderr, "Match %d `%s' from %d(%ld,%ld) to %d(%ld,%ld) (%d).\n",
1676                                                 j, match,
1677                                                 matches[j].rm_so + coffset,
1678                                                 sattr->column,
1679                                                 sattr->row,
1680                                                 matches[j].rm_eo + coffset - 1,
1681                                                 eattr->column,
1682                                                 eattr->row,
1683                                                 offset);
1684                                         g_free(match);
1685
1686                                 }
1687 #endif
1688                                 /* Snip off any final newlines. */
1689                                 while ((matches[j].rm_eo > matches[j].rm_so) &&
1690                                        (terminal->pvt->match_contents[coffset + matches[j].rm_eo - 1] == '\n')) {
1691                                         matches[j].rm_eo--;
1692                                 }
1693                                 /* If the pointer is in this substring,
1694                                  * then we're done. */
1695                                 if ((offset >= (matches[j].rm_so + coffset)) &&
1696                                     (offset < (matches[j].rm_eo + coffset))) {
1697                                         if (tag != NULL) {
1698                                                 *tag = regex->tag;
1699                                         }
1700                                         if (start != NULL) {
1701                                                 *start = coffset +
1702                                                          matches[j].rm_so;
1703                                         }
1704                                         if (end != NULL) {
1705                                                 *end = coffset +
1706                                                        matches[j].rm_eo - 1;
1707                                         }
1708                                         if (GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
1709                                                 gdk_window_set_cursor((GTK_WIDGET(terminal))->window,
1710                                                                       regex->cursor);
1711                                         }
1712                                         terminal->pvt->match_previous = regex->tag;
1713                                         return g_strndup(terminal->pvt->match_contents + coffset + matches[j].rm_so,
1714                                                          matches[j].rm_eo - matches[j].rm_so);
1715                                 }
1716                         }
1717                         /* Skip past the beginning of this match to
1718                          * look for more. */
1719                         coffset += (matches[0].rm_so + 1);
1720                         ret = _vte_regex_exec(regex->reg,
1721                                               terminal->pvt->match_contents +
1722                                               coffset,
1723                                               G_N_ELEMENTS(matches),
1724                                               matches);
1725                 }
1726         }
1727         terminal->pvt->match_previous = -1;
1728         return NULL;
1729 }
1730
1731 /**
1732  * vte_terminal_match_check:
1733  * @terminal: a #VteTerminal
1734  * @column: the text column
1735  * @row: the text row
1736  * @tag: pointer to an integer
1737  *
1738  * Checks if the text in and around the specified position matches any of the
1739  * regular expressions previously set using vte_terminal_match_add().  If a
1740  * match exists, the text string is returned and if @tag is not NULL, the number
1741  * associated with the matched regular expression will be stored in @tag.
1742  *
1743  * If more than one regular expression has been set with
1744  * vte_terminal_match_add(), then expressions are checked in the order in
1745  * which they were added.
1746  *
1747  * Returns: a string which matches one of the previously set regular
1748  * expressions, and which must be freed by the caller.
1749  */
1750 char *
1751 vte_terminal_match_check(VteTerminal *terminal, glong column, glong row,
1752                          int *tag)
1753 {
1754         long delta;
1755         char *ret;
1756         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1757         delta = terminal->pvt->screen->scroll_delta;
1758 #ifdef VTE_DEBUG
1759         if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1760                 fprintf(stderr, "Checking for match at (%ld,%ld).\n",
1761                         row, column);
1762         }
1763 #endif
1764         ret = vte_terminal_match_check_internal(terminal,
1765                                                 column, row + delta,
1766                                                 tag, NULL, NULL);
1767 #ifdef VTE_DEBUG
1768         if ((ret != NULL) && _vte_debug_on(VTE_DEBUG_EVENTS)) {
1769                 fprintf(stderr, "Matched `%s'.\n", ret);
1770         }
1771 #endif
1772         return ret;
1773 }
1774
1775 /* Emit an adjustment changed signal on our adjustment object. */
1776 static gboolean
1777 vte_terminal_emit_adjustment_changed(gpointer data)
1778 {
1779         VteTerminal *terminal;
1780         terminal = VTE_TERMINAL(data);
1781         if (terminal->pvt->adjustment_changed_tag) {
1782 #ifdef VTE_DEBUG
1783                 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1784                         fprintf(stderr, "Emitting adjustment_changed.\n");
1785                 }
1786 #endif
1787                 terminal->pvt->adjustment_changed_tag = 0;
1788                 gtk_adjustment_changed(terminal->adjustment);
1789         }
1790         return FALSE;
1791 }
1792
1793 /* Queue an adjustment-changed signal to be delivered when convenient. */
1794 static void
1795 vte_terminal_queue_adjustment_changed(VteTerminal *terminal)
1796 {
1797         if (terminal->pvt->adjustment_changed_tag == 0) {
1798                 terminal->pvt->adjustment_changed_tag =
1799                                 g_idle_add_full(VTE_ADJUSTMENT_PRIORITY,
1800                                                 vte_terminal_emit_adjustment_changed,
1801                                                 terminal,
1802                                                 NULL);
1803         } else {
1804 #ifdef VTE_DEBUG
1805                 if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1806                         fprintf(stderr, "Swallowing duplicate "
1807                                 "adjustment-changed signal.\n");
1808                 }
1809 #endif
1810         }
1811 }
1812
1813 /* Update the adjustment field of the widget.  This function should be called
1814  * whenever we add rows to or remove rows from the history or switch screens. */
1815 static void
1816 vte_terminal_adjust_adjustments(VteTerminal *terminal, gboolean immediate)
1817 {
1818         VteScreen *screen;
1819         gboolean changed;
1820         long delta;
1821         long rows;
1822
1823         g_return_if_fail(terminal->pvt->screen != NULL);
1824         g_return_if_fail(terminal->pvt->screen->row_data != NULL);
1825
1826         /* Adjust the vertical, uh, adjustment. */
1827         changed = FALSE;
1828
1829         /* The lower value should be the first row in the buffer. */
1830         screen = terminal->pvt->screen;
1831         delta = _vte_ring_delta(screen->row_data);
1832 #ifdef VTE_DEBUG
1833         if (_vte_debug_on(VTE_DEBUG_IO)) {
1834                 fprintf(stderr, "Changing adjustment values "
1835                         "(delta = %ld, scroll = %ld).\n",
1836                         delta, screen->scroll_delta);
1837         }
1838 #endif
1839         if (terminal->adjustment->lower != delta) {
1840                 terminal->adjustment->lower = delta;
1841                 changed = TRUE;
1842         }
1843
1844         /* Snap the insert delta and the cursor position to be in the visible
1845          * area.  Leave the scrolling delta alone because it will be updated
1846          * when the adjustment changes. */
1847         screen->insert_delta = MAX(screen->insert_delta, delta);
1848         screen->cursor_current.row = MAX(screen->cursor_current.row,
1849                                          screen->insert_delta);
1850
1851         /* The upper value is the number of rows which might be visible.  (Add
1852          * one to the cursor offset because it's zero-based.) */
1853         rows = MAX(_vte_ring_next(terminal->pvt->screen->row_data),
1854                    terminal->pvt->screen->cursor_current.row + 1);
1855         if (terminal->adjustment->upper != rows) {
1856                 terminal->adjustment->upper = rows;
1857                 changed = TRUE;
1858         }
1859
1860         /* The step increment should always be one. */
1861         if (terminal->adjustment->step_increment != 1) {
1862                 terminal->adjustment->step_increment = 1;
1863                 changed = TRUE;
1864         }
1865
1866         /* Set the number of rows the user sees to the number of rows the
1867          * user sees. */
1868         if (terminal->adjustment->page_size != terminal->row_count) {
1869                 terminal->adjustment->page_size = terminal->row_count;
1870                 changed = TRUE;
1871         }
1872
1873         /* Clicking in the empty area should scroll one screen, so set the
1874          * page size to the number of visible rows. */
1875         if (terminal->adjustment->page_increment != terminal->row_count) {
1876                 terminal->adjustment->page_increment = terminal->row_count;
1877                 changed = TRUE;
1878         }
1879
1880         /* Set the scrollbar adjustment to where the screen wants it to be. */
1881         if (floor(terminal->adjustment->value) !=
1882             terminal->pvt->screen->scroll_delta) {
1883                 /* This emits a "value-changed" signal, so no need to screw
1884                  * with anything else for just this. */
1885                 gtk_adjustment_set_value(terminal->adjustment,
1886                                          terminal->pvt->screen->scroll_delta);
1887         }
1888
1889         /* If anything changed, signal that there was a change. */
1890         if (changed == TRUE) {
1891 #ifdef VTE_DEBUG
1892                 if (_vte_debug_on(VTE_DEBUG_IO)) {
1893                         fprintf(stderr, "Changed adjustment values "
1894                                 "(delta = %ld, scroll = %ld).\n",
1895                                 delta, terminal->pvt->screen->scroll_delta);
1896                 }
1897 #endif
1898                 if (immediate) {
1899                         gtk_adjustment_changed(terminal->adjustment);
1900                 } else {
1901                         vte_terminal_queue_adjustment_changed(terminal);
1902                 }
1903         }
1904 }
1905
1906 /* Scroll up or down in the current screen. */
1907 static void
1908 vte_terminal_scroll_pages(VteTerminal *terminal, gint pages)
1909 {
1910         glong destination;
1911         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1912 #ifdef VTE_DEBUG
1913         if (_vte_debug_on(VTE_DEBUG_IO)) {
1914                 fprintf(stderr, "Scrolling %d pages.\n", pages);
1915         }
1916 #endif
1917         /* Calculate the ideal position where we want to be before clamping. */
1918         destination = floor(gtk_adjustment_get_value(terminal->adjustment));
1919         destination += (pages * terminal->row_count);
1920         /* Can't scroll past data we have. */
1921         destination = CLAMP(destination,
1922                             terminal->adjustment->lower,
1923                             terminal->adjustment->upper - terminal->row_count);
1924         /* Tell the scrollbar to adjust itself. */
1925         gtk_adjustment_set_value(terminal->adjustment, destination);
1926         /* Clear dingus match set. */
1927         vte_terminal_match_contents_clear(terminal);
1928         /* Notify viewers that the contents have changed. */
1929         vte_terminal_emit_contents_changed(terminal);
1930 }
1931
1932 /* Scroll so that the scroll delta is the minimum value. */
1933 static void
1934 vte_terminal_maybe_scroll_to_top(VteTerminal *terminal)
1935 {
1936         long delta;
1937         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1938         if (floor(gtk_adjustment_get_value(terminal->adjustment)) !=
1939             _vte_ring_delta(terminal->pvt->screen->row_data)) {
1940                 delta = _vte_ring_delta(terminal->pvt->screen->row_data);
1941                 gtk_adjustment_set_value(terminal->adjustment, delta);
1942         }
1943 }
1944
1945 /* Scroll so that the scroll delta is the insertion delta. */
1946 static void
1947 vte_terminal_maybe_scroll_to_bottom(VteTerminal *terminal)
1948 {
1949         glong delta;
1950         g_return_if_fail(VTE_IS_TERMINAL(terminal));
1951         if (floor(gtk_adjustment_get_value(terminal->adjustment)) !=
1952             terminal->pvt->screen->insert_delta) {
1953                 delta = terminal->pvt->screen->insert_delta;
1954                 gtk_adjustment_set_value(terminal->adjustment, delta);
1955         }
1956 }
1957
1958 /* Call another function, offsetting any long arguments by the given
1959  * increment value. */
1960 static gboolean
1961 vte_sequence_handler_offset(VteTerminal *terminal,
1962                             const char *match,
1963                             GQuark match_quark,
1964                             GValueArray *params,
1965                             int increment,
1966                             VteTerminalSequenceHandler handler)
1967 {
1968         guint i;
1969         long val;
1970         GValue *value;
1971         /* Decrement the parameters and let the _cs handler deal with it. */
1972         for (i = 0; (params != NULL) && (i < params->n_values); i++) {
1973                 value = g_value_array_get_nth(params, i);
1974                 if (G_VALUE_HOLDS_LONG(value)) {
1975                         val = g_value_get_long(value);
1976                         val += increment;
1977                         g_value_set_long(value, val);
1978                 }
1979         }
1980         return handler(terminal, match, match_quark, params);
1981 }
1982
1983 /* Call another function a given number of times, or once. */
1984 static gboolean
1985 vte_sequence_handler_multiple(VteTerminal *terminal,
1986                               const char *match,
1987                               GQuark match_quark,
1988                               GValueArray *params,
1989                               VteTerminalSequenceHandler handler)
1990 {
1991         long val = 1;
1992         int i, again;
1993         GValue *value;
1994
1995         if ((params != NULL) && (params->n_values > 0)) {
1996                 value = g_value_array_get_nth(params, 0);
1997                 if (G_VALUE_HOLDS_LONG(value)) {
1998                         val = g_value_get_long(value);
1999                         val = MAX(val, 1);      /* FIXME: vttest. */
2000                 }
2001         }
2002         again = 0;
2003         for (i = 0; i < val; i++) {
2004                 if (handler(terminal, match, match_quark, NULL)) {
2005                         again++;
2006                 }
2007         }
2008         return (again > 0);
2009 }
2010
2011 /* Insert a blank line at an arbitrary position. */
2012 static void
2013 vte_insert_line_internal(VteTerminal *terminal, glong position)
2014 {
2015         VteRowData *row;
2016         /* Pad out the line data to the insertion point. */
2017         while (_vte_ring_next(terminal->pvt->screen->row_data) < position) {
2018                 row = vte_new_row_data_sized(terminal, TRUE);
2019                 _vte_ring_append(terminal->pvt->screen->row_data, row);
2020         }
2021         /* If we haven't inserted a line yet, insert a new one. */
2022         row = vte_new_row_data_sized(terminal, TRUE);
2023         if (_vte_ring_next(terminal->pvt->screen->row_data) >= position) {
2024                 _vte_ring_insert(terminal->pvt->screen->row_data,
2025                                  position, row);
2026         } else {
2027                 _vte_ring_append(terminal->pvt->screen->row_data, row);
2028         }
2029 }
2030
2031 /* Remove a line at an arbitrary position. */
2032 static void
2033 vte_remove_line_internal(VteTerminal *terminal, glong position)
2034 {
2035         if (_vte_ring_next(terminal->pvt->screen->row_data) > position) {
2036                 _vte_ring_remove(terminal->pvt->screen->row_data,
2037                                  position, TRUE);
2038         }
2039 }
2040
2041 /**
2042  * vte_terminal_set_encoding:
2043  * @terminal: a #VteTerminal
2044  * @codeset: a valid #g_iconv target
2045  *
2046  * Changes the encoding the terminal will expect data from the child to
2047  * be encoded with.  For certain terminal types, applications executing in the
2048  * terminal can change the encoding.  The default encoding is defined by the
2049  * application's locale settings.
2050  *
2051  */
2052 void
2053 vte_terminal_set_encoding(VteTerminal *terminal, const char *codeset)
2054 {
2055         const char *old_codeset;
2056         GQuark encoding_quark;
2057         VteConv conv;
2058         char *obuf1, *obuf2;
2059         gsize bytes_written;
2060
2061         old_codeset = terminal->pvt->encoding;
2062         if (codeset == NULL) {
2063                 g_get_charset(&codeset);
2064         }
2065         if ((old_codeset != NULL) && (strcmp(codeset, old_codeset) == 0)) {
2066                 /* Nothing to do! */
2067                 return;
2068         }
2069
2070         /* Open new conversions. */
2071         conv = _vte_conv_open(codeset, "UTF-8");
2072         if (conv == ((VteConv) -1)) {
2073                 g_warning(_("Unable to convert characters from %s to %s."),
2074                           "UTF-8", codeset);
2075                 return;
2076         }
2077         if (terminal->pvt->outgoing_conv != (VteConv) -1) {
2078                 _vte_conv_close(terminal->pvt->outgoing_conv);
2079         }
2080         terminal->pvt->outgoing_conv = conv;
2081
2082         /* Set the terminal's encoding to the new value. */
2083         encoding_quark = g_quark_from_string(codeset);
2084         terminal->pvt->encoding = g_quark_to_string(encoding_quark);
2085
2086         /* Convert any buffered output bytes. */
2087         if ((_vte_buffer_length(terminal->pvt->outgoing) > 0) &&
2088             (old_codeset != NULL)) {
2089                 /* Convert back to UTF-8. */
2090                 obuf1 = g_convert(terminal->pvt->outgoing->bytes,
2091                                   _vte_buffer_length(terminal->pvt->outgoing),
2092                                   "UTF-8",
2093                                   old_codeset,
2094                                   NULL,
2095                                   &bytes_written,
2096                                   NULL);
2097                 if (obuf1 != NULL) {
2098                         /* Convert to the new encoding. */
2099                         obuf2 = g_convert(obuf1,
2100                                           bytes_written,
2101                                           codeset,
2102                                           "UTF-8",
2103                                           NULL,
2104                                           &bytes_written,
2105                                           NULL);
2106                         if (obuf2 != NULL) {
2107                                 _vte_buffer_clear(terminal->pvt->outgoing);
2108                                 _vte_buffer_append(terminal->pvt->outgoing,
2109                                                    obuf2, bytes_written);
2110                                 g_free(obuf2);
2111                         }
2112                         g_free(obuf1);
2113                 }
2114         }
2115
2116         /* Set the encoding for incoming text. */
2117         _vte_iso2022_state_set_codeset(terminal->pvt->iso2022,
2118                                        terminal->pvt->encoding);
2119
2120 #ifdef VTE_DEBUG
2121         if (_vte_debug_on(VTE_DEBUG_IO)) {
2122                 fprintf(stderr, "Set terminal encoding to `%s'.\n",
2123                         terminal->pvt->encoding);
2124         }
2125 #endif
2126         vte_terminal_emit_encoding_changed(terminal);
2127 }
2128
2129 /**
2130  * vte_terminal_get_encoding:
2131  * @terminal: a #VteTerminal
2132  *
2133  * Determines the name of the encoding in which the terminal expects data to be
2134  * encoded.
2135  *
2136  * Returns: the current encoding for the terminal.
2137  */
2138 const char *
2139 vte_terminal_get_encoding(VteTerminal *terminal)
2140 {
2141         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
2142         return terminal->pvt->encoding;
2143 }
2144
2145 /* End alternate character set. */
2146 static gboolean
2147 vte_sequence_handler_ae(VteTerminal *terminal,
2148                         const char *match,
2149                         GQuark match_quark,
2150                         GValueArray *params)
2151 {
2152         terminal->pvt->screen->defaults.alternate = 0;
2153         return FALSE;
2154 }
2155
2156 /* Add a line at the current cursor position. */
2157 static gboolean
2158 vte_sequence_handler_al(VteTerminal *terminal,
2159                         const char *match,
2160                         GQuark match_quark,
2161                         GValueArray *params)
2162 {
2163         VteScreen *screen;
2164         VteRowData *rowdata;
2165         long start, end, param, i;
2166         GValue *value;
2167
2168         /* Find out which part of the screen we're messing with. */
2169         screen = terminal->pvt->screen;
2170         start = screen->cursor_current.row;
2171         if (screen->scrolling_restricted) {
2172                 end = screen->insert_delta + screen->scrolling_region.end;
2173         } else {
2174                 end = screen->insert_delta + terminal->row_count - 1;
2175         }
2176
2177         /* Extract any parameters. */
2178         param = 1;
2179         if ((params != NULL) && (params->n_values > 0)) {
2180                 value = g_value_array_get_nth(params, 0);
2181                 param = g_value_get_long(value);
2182         }
2183
2184         /* Insert the right number of lines. */
2185         for (i = 0; i < param; i++) {
2186                 /* Clear a line off the end of the region and add one to the
2187                  * top of the region. */
2188                 vte_remove_line_internal(terminal, end);
2189                 vte_insert_line_internal(terminal, start);
2190                 /* Get the data for the new row. */
2191                 rowdata = _vte_ring_index(screen->row_data,
2192                                           VteRowData *, start);
2193                 /* Add enough cells to it so that it has the default colors. */
2194                 vte_g_array_fill(rowdata->cells, &screen->fill_defaults,
2195                                  terminal->column_count);
2196                 /* Adjust the scrollbars if necessary. */
2197                 vte_terminal_adjust_adjustments(terminal, FALSE);
2198         }
2199
2200         /* Update the display. */
2201         vte_terminal_scroll_region(terminal, start, end - start + 1, param);
2202
2203         /* We've modified the display.  Make a note of it. */
2204         terminal->pvt->text_deleted_count++;
2205         return FALSE;
2206 }
2207
2208 /* Add N lines at the current cursor position. */
2209 static gboolean
2210 vte_sequence_handler_AL(VteTerminal *terminal,
2211                         const char *match,
2212                         GQuark match_quark,
2213                         GValueArray *params)
2214 {
2215         return vte_sequence_handler_al(terminal, match, match_quark, params);
2216 }
2217
2218 /* Start using alternate character set. */
2219 static gboolean
2220 vte_sequence_handler_as(VteTerminal *terminal,
2221                         const char *match,
2222                         GQuark match_quark,
2223                         GValueArray *params)
2224 {
2225         terminal->pvt->screen->defaults.alternate = 1;
2226         return FALSE;
2227 }
2228
2229 static void
2230 vte_terminal_beep(VteTerminal *terminal)
2231 {
2232 #if GTK_CHECK_VERSION(2,2,0)
2233         GdkDisplay *display;
2234
2235         g_return_if_fail(VTE_IS_TERMINAL(terminal));
2236         display = gtk_widget_get_display(GTK_WIDGET(terminal));
2237         gdk_display_beep(display);
2238 #else
2239         gdk_beep();
2240 #endif
2241 }
2242
2243 /* Beep. */
2244 static gboolean
2245 vte_sequence_handler_bl(VteTerminal *terminal,
2246                         const char *match,
2247                         GQuark match_quark,
2248                         GValueArray *params)
2249 {
2250         if (terminal->pvt->audible_bell) {
2251                 /* Feep. */
2252                 vte_terminal_beep(terminal);
2253         }
2254         if (terminal->pvt->visible_bell) {
2255                 /* Visual bell. */
2256                 vte_sequence_handler_vb(terminal, match, match_quark, params);
2257         }
2258         return FALSE;
2259 }
2260
2261 /* Backtab. */
2262 static gboolean
2263 vte_sequence_handler_bt(VteTerminal *terminal,
2264                         const char *match,
2265                         GQuark match_quark,
2266                         GValueArray *params)
2267 {
2268         long newcol;
2269
2270         /* Calculate which column is the previous tab stop. */
2271         newcol = terminal->pvt->screen->cursor_current.col;
2272
2273         if (terminal->pvt->tabstops != NULL) {
2274                 /* Find the next tabstop. */
2275                 while (newcol >= 0) {
2276                         if (vte_terminal_get_tabstop(terminal,
2277                                                      newcol % terminal->column_count)) {
2278                                 break;
2279                         }
2280                         newcol--;
2281                 }
2282         }
2283
2284         /* If we have no tab stops, stop at the first column. */
2285         if (newcol <= 0) {
2286                 newcol = 0;
2287         }
2288
2289         /* Warp the cursor. */
2290 #ifdef VTE_DEBUG
2291         if (_vte_debug_on(VTE_DEBUG_PARSE)) {
2292                 fprintf(stderr, "Moving cursor to column %ld.\n", (long)newcol);
2293         }
2294 #endif
2295         terminal->pvt->screen->cursor_current.col = newcol;
2296         return FALSE;
2297 }
2298
2299 /* Clear from the cursor position to the beginning of the line. */
2300 static gboolean
2301 vte_sequence_handler_cb(VteTerminal *terminal,
2302                         const char *match,
2303                         GQuark match_quark,
2304                         GValueArray *params)
2305 {
2306         VteRowData *rowdata;
2307         long i;
2308         VteScreen *screen;
2309         struct vte_charcell *pcell;
2310         screen = terminal->pvt->screen;
2311
2312         /* Get the data for the row which the cursor points to. */
2313         vte_terminal_ensure_cursor(terminal, FALSE);
2314         rowdata = _vte_ring_index(screen->row_data,
2315                                   VteRowData *,
2316                                   screen->cursor_current.row);
2317         /* Clear the data up to the current column with the default
2318          * attributes.  If there is no such character cell, we need
2319          * to add one. */
2320         for (i = 0; i <= screen->cursor_current.col; i++) {
2321                 if (i < rowdata->cells->len) {
2322                         /* Muck with the cell in this location. */
2323                         pcell = &g_array_index(rowdata->cells,
2324                                                struct vte_charcell,
2325                                                i);
2326                         *pcell = screen->color_defaults;
2327                 } else {
2328                         /* Add new cells until we have one here. */
2329                         g_array_append_val(rowdata->cells,
2330                                            screen->color_defaults);
2331                 }
2332         }
2333         /* Repaint this row. */
2334         vte_invalidate_cells(terminal,
2335                              0, terminal->column_count,
2336                              screen->cursor_current.row, 1);
2337
2338         /* We've modified the display.  Make a note of it. */
2339         terminal->pvt->text_deleted_count++;
2340         return FALSE;
2341 }
2342
2343 /* Clear to the right of the cursor and below the current line. */
2344 static gboolean
2345 vte_sequence_handler_cd(VteTerminal *terminal,
2346                         const char *match,
2347                         GQuark match_quark,
2348                         GValueArray *params)
2349 {
2350         VteRowData *rowdata;
2351         long i;
2352         VteScreen *screen;
2353
2354         screen = terminal->pvt->screen;
2355         /* If the cursor is actually on the screen, clear the rest of the
2356          * row the cursor is on and all of the rows below the cursor. */
2357         i = screen->cursor_current.row;
2358         if (i < _vte_ring_next(screen->row_data)) {
2359                 /* Get the data for the row we're clipping. */
2360                 rowdata = _vte_ring_index(screen->row_data, VteRowData *, i);
2361                 /* Clear everything to the right of the cursor. */
2362                 if ((rowdata != NULL) &&
2363                     (rowdata->cells->len > screen->cursor_current.col)) {
2364                         g_array_set_size(rowdata->cells,
2365                                          screen->cursor_current.col);
2366                 }
2367         }
2368         /* Now for the rest of the lines. */
2369         for (i = screen->cursor_current.row + 1;
2370              i < _vte_ring_next(screen->row_data);
2371              i++) {
2372                 /* Get the data for the row we're removing. */
2373                 rowdata = _vte_ring_index(screen->row_data, VteRowData *, i);
2374                 /* Remove it. */
2375                 if ((rowdata != NULL) && (rowdata->cells->len > 0)) {
2376                         g_array_set_size(rowdata->cells, 0);
2377                 }
2378         }
2379         /* Now fill the cleared areas. */
2380         for (i = screen->cursor_current.row;
2381              i < screen->insert_delta + terminal->row_count;
2382              i++) {
2383                 /* Retrieve the row's data, creating it if necessary. */
2384                 if (_vte_ring_contains(screen->row_data, i)) {
2385                         rowdata = _vte_ring_index(screen->row_data,
2386                                                   VteRowData *, i);
2387                 } else {
2388                         rowdata = vte_new_row_data(terminal);
2389                         _vte_ring_append(screen->row_data, rowdata);
2390                 }
2391                 /* Pad out the row. */
2392                 vte_g_array_fill(rowdata->cells,
2393                                  &screen->fill_defaults,
2394                                  terminal->column_count);
2395                 /* Repaint this row. */
2396                 vte_invalidate_cells(terminal,
2397                                      0, terminal->column_count,
2398                                      i, 1);
2399         }
2400
2401         /* We've modified the display.  Make a note of it. */
2402         terminal->pvt->text_deleted_count++;
2403         return FALSE;
2404 }
2405
2406 /* Clear from the cursor position to the end of the line. */
2407 static gboolean
2408 vte_sequence_handler_ce(VteTerminal *terminal,
2409                         const char *match,
2410                         GQuark match_quark,
2411                         GValueArray *params)
2412 {
2413         VteRowData *rowdata;
2414         VteScreen *screen;
2415
2416         screen = terminal->pvt->screen;
2417         /* Get the data for the row which the cursor points to. */
2418         vte_terminal_ensure_cursor(terminal, FALSE);
2419         rowdata = _vte_ring_index(screen->row_data, VteRowData *,
2420                                   screen->cursor_current.row);
2421         /* Remove the data at the end of the array until the current column
2422          * is the end of the array. */
2423         if (rowdata->cells->len > screen->cursor_current.col) {
2424                 g_array_set_size(rowdata->cells, screen->cursor_current.col);
2425         }
2426         /* Add enough cells to the end of the line to fill out the row. */
2427         vte_g_array_fill(rowdata->cells,
2428                          &screen->fill_defaults,
2429                          terminal->column_count);
2430         /* Repaint this row. */
2431         vte_invalidate_cells(terminal,
2432                              0, terminal->column_count,
2433                              screen->cursor_current.row, 1);
2434
2435         /* We've modified the display.  Make a note of it. */
2436         terminal->pvt->text_deleted_count++;
2437         return FALSE;
2438 }
2439
2440 /* Move the cursor to the given column (horizontal position). */
2441 static gboolean
2442 vte_sequence_handler_ch(VteTerminal *terminal,
2443                         const char *match,
2444                         GQuark match_quark,
2445                         GValueArray *params)
2446 {
2447         VteScreen *screen;
2448         GValue *value;
2449         long val;
2450
2451         screen = terminal->pvt->screen;
2452         /* We only care if there's a parameter in there. */
2453         if ((params != NULL) && (params->n_values > 0)) {
2454                 value = g_value_array_get_nth(params, 0);
2455                 if (G_VALUE_HOLDS_LONG(value)) {
2456                         val = CLAMP(g_value_get_long(value),
2457                                     0,
2458                                     terminal->column_count - 1);
2459                         /* Move the cursor. */
2460                         screen->cursor_current.col = val;
2461                 }
2462         }
2463         return FALSE;
2464 }
2465
2466 /* Clear the screen and home the cursor. */
2467 static gboolean
2468 vte_sequence_handler_cl(VteTerminal *terminal,
2469                         const char *match,
2470                         GQuark match_quark,
2471                         GValueArray *params)
2472 {
2473         vte_sequence_handler_clear_screen(terminal, NULL, 0, NULL);
2474         vte_sequence_handler_ho(terminal, NULL, 0, NULL);
2475
2476         /* We've modified the display.  Make a note of it. */
2477         terminal->pvt->text_deleted_count++;
2478         return FALSE;
2479 }
2480
2481 /* Move the cursor to the given position. */
2482 static gboolean
2483 vte_sequence_handler_cm(VteTerminal *terminal,
2484                         const char *match,
2485                         GQuark match_quark,
2486                         GValueArray *params)
2487 {
2488         GValue *row, *col;
2489         long rowval, colval, origin;
2490         VteScreen *screen;
2491
2492         screen = terminal->pvt->screen;
2493         /* We need at least two parameters. */
2494         if ((params != NULL) && (params->n_values >= 2)) {
2495                 /* The first is the row, the second is the column. */
2496                 row = g_value_array_get_nth(params, 0);
2497                 col = g_value_array_get_nth(params, 1);
2498                 if (G_VALUE_HOLDS_LONG(row) &&
2499                     G_VALUE_HOLDS_LONG(col)) {
2500                         if (screen->origin_mode &&
2501                             screen->scrolling_restricted) {
2502                                 origin = screen->scrolling_region.start;
2503                         } else {
2504                                 origin = 0;
2505                         }
2506                         rowval = g_value_get_long(row) + origin;
2507                         colval = g_value_get_long(col);
2508                         rowval = CLAMP(rowval, 0, terminal->row_count - 1);
2509                         colval = CLAMP(colval, 0, terminal->column_count - 1);
2510                         screen->cursor_current.row = rowval +
2511                                                      screen->insert_delta;
2512                         screen->cursor_current.col = colval;
2513                 }
2514         }
2515         return FALSE;
2516 }
2517
2518 /* Clear the current line. */
2519 static gboolean
2520 vte_sequence_handler_clear_current_line(VteTerminal *terminal,
2521                                         const char *match,
2522                                         GQuark match_quark,
2523                                         GValueArray *params)
2524 {
2525         VteRowData *rowdata;
2526         VteScreen *screen;
2527
2528         screen = terminal->pvt->screen;
2529
2530         /* If the cursor is actually on the screen, clear data in the row
2531          * which corresponds to the cursor. */
2532         if (_vte_ring_next(screen->row_data) > screen->cursor_current.row) {
2533                 /* Get the data for the row which the cursor points to. */
2534                 rowdata = _vte_ring_index(screen->row_data, VteRowData *,
2535                                           screen->cursor_current.row);
2536                 /* Remove it. */
2537                 if (rowdata->cells->len > 0) {
2538                         g_array_set_size(rowdata->cells, 0);
2539                 }
2540                 /* Add enough cells to the end of the line to fill out the
2541                  * row. */
2542                 vte_g_array_fill(rowdata->cells,
2543                                  &screen->fill_defaults,
2544                                  terminal->column_count);
2545                 /* Repaint this row. */
2546                 vte_invalidate_cells(terminal,
2547                                      0, terminal->column_count,
2548                                      screen->cursor_current.row, 1);
2549         }
2550
2551         /* We've modified the display.  Make a note of it. */
2552         terminal->pvt->text_deleted_count++;
2553         return FALSE;
2554 }
2555
2556 /* Carriage return. */
2557 static gboolean
2558 vte_sequence_handler_cr(VteTerminal *terminal,
2559                         const char *match,
2560                         GQuark match_quark,
2561                         GValueArray *params)
2562 {
2563         terminal->pvt->screen->cursor_current.col = 0;
2564         return FALSE;
2565 }
2566
2567 /* Restrict scrolling and updates to a subset of the visible lines. */
2568 static gboolean
2569 vte_sequence_handler_cs(VteTerminal *terminal,
2570                         const char *match,
2571                         GQuark match_quark,
2572                         GValueArray *params)
2573 {
2574         long start, end, rows;
2575         GValue *value;
2576         VteScreen *screen;
2577
2578         /* We require two parameters.  Anything less is a reset. */
2579         screen = terminal->pvt->screen;
2580         if ((params == NULL) || (params->n_values < 2)) {
2581                 screen->scrolling_restricted = FALSE;
2582                 return FALSE;
2583         }
2584         /* Extract the two values. */
2585         value = g_value_array_get_nth(params, 0);
2586         start = g_value_get_long(value);
2587         value = g_value_array_get_nth(params, 1);
2588         end = g_value_get_long(value);
2589         /* Catch garbage. */
2590         rows = terminal->row_count;
2591         if ((start <= 0) || (start >= rows)) {
2592                 start = 0;
2593         }
2594         if ((end <= 0) || (end >= rows)) {
2595                 end = rows - 1;
2596         }
2597         /* Set the right values. */
2598         screen->scrolling_region.start = start;
2599         screen->scrolling_region.end = end;
2600         screen->scrolling_restricted = TRUE;
2601         /* Special case -- run wild, run free. */
2602         if ((screen->scrolling_region.start == 0) &&
2603             (screen->scrolling_region.end == rows - 1)) {
2604                 screen->scrolling_restricted = FALSE;
2605         }
2606         /* Clamp the cursor to the scrolling region. */
2607         screen->cursor_current.row = CLAMP(screen->cursor_current.row,
2608                                            screen->insert_delta + start,
2609                                            screen->insert_delta + end);
2610         vte_terminal_ensure_cursor(terminal, TRUE);
2611         return FALSE;
2612 }
2613
2614 /* Restrict scrolling and updates to a subset of the visible lines, because
2615  * GNU Emacs is special. */
2616 static gboolean
2617 vte_sequence_handler_cS(VteTerminal *terminal,
2618                         const char *match,
2619                         GQuark match_quark,
2620                         GValueArray *params)
2621 {
2622         long start, end, rows;
2623         GValue *value;
2624         VteScreen *screen;
2625
2626         /* We require four parameters. */
2627         screen = terminal->pvt->screen;
2628         if ((params == NULL) || (params->n_values < 2)) {
2629                 screen->scrolling_restricted = FALSE;
2630                 return FALSE;
2631         }
2632         /* Extract the two parameters we care about, encoded as the number
2633          * of lines above and below the scrolling region, respectively. */
2634         value = g_value_array_get_nth(params, 1);
2635         start = g_value_get_long(value);
2636         value = g_value_array_get_nth(params, 2);
2637         end = (terminal->row_count - 1) - g_value_get_long(value);
2638         /* Set the right values. */
2639         screen->scrolling_region.start = start;
2640         screen->scrolling_region.end = end;
2641         screen->scrolling_restricted = TRUE;
2642         /* Special case -- run wild, run free. */
2643         rows = terminal->row_count;
2644         if ((screen->scrolling_region.start == 0) &&
2645             (screen->scrolling_region.end == rows - 1)) {
2646                 screen->scrolling_restricted = FALSE;
2647         }
2648         /* Clamp the cursor to the scrolling region. */
2649         screen->cursor_current.row = CLAMP(screen->cursor_current.row,
2650                                            screen->insert_delta + start,
2651                                            screen->insert_delta + end);
2652         vte_terminal_ensure_cursor(terminal, TRUE);
2653         return FALSE;
2654 }
2655
2656 /* Clear all tab stops. */
2657 static gboolean
2658 vte_sequence_handler_ct(VteTerminal *terminal,
2659                         const char *match,
2660                         GQuark match_quark,
2661                         GValueArray *params)
2662 {
2663         if (terminal->pvt->tabstops != NULL) {
2664                 g_hash_table_destroy(terminal->pvt->tabstops);
2665                 terminal->pvt->tabstops = NULL;
2666         }
2667         return FALSE;
2668 }
2669
2670 /* Move the cursor to the lower left-hand corner. */
2671 static gboolean
2672 vte_sequence_handler_cursor_lower_left(VteTerminal *terminal,
2673                                        const char *match,
2674                                        GQuark match_quark,
2675                                        GValueArray *params)
2676 {
2677         VteScreen *screen;
2678         long row;
2679         screen = terminal->pvt->screen;
2680         row = MAX(0, terminal->row_count - 1);
2681         screen->cursor_current.row = screen->insert_delta + row;
2682         screen->cursor_current.col = 0;
2683         vte_terminal_ensure_cursor(terminal, TRUE);
2684         return FALSE;
2685 }
2686
2687 /* Move the cursor to the beginning of the next line, scrolling if necessary. */
2688 static gboolean
2689 vte_sequence_handler_cursor_next_line(VteTerminal *terminal,
2690                                       const char *match,
2691                                       GQuark match_quark,
2692                                       GValueArray *params)
2693 {
2694         terminal->pvt->screen->cursor_current.col = 0;
2695         return vte_sequence_handler_DO(terminal, match, match_quark, params);
2696 }
2697
2698 /* Move the cursor to the beginning of the next line, scrolling if necessary. */
2699 static gboolean
2700 vte_sequence_handler_cursor_preceding_line(VteTerminal *terminal,
2701                                            const char *match,
2702                                            GQuark match_quark,
2703                                            GValueArray *params)
2704 {
2705         terminal->pvt->screen->cursor_current.col = 0;
2706         return vte_sequence_handler_UP(terminal, match, match_quark, params);
2707 }
2708
2709 /* Move the cursor to the given row (vertical position). */
2710 static gboolean
2711 vte_sequence_handler_cv(VteTerminal *terminal,
2712                         const char *match,
2713                         GQuark match_quark,
2714                         GValueArray *params)
2715 {
2716         VteScreen *screen;
2717         GValue *value;
2718         long val, origin;
2719         screen = terminal->pvt->screen;
2720         /* We only care if there's a parameter in there. */
2721         if ((params != NULL) && (params->n_values > 0)) {
2722                 value = g_value_array_get_nth(params, 0);
2723                 if (G_VALUE_HOLDS_LONG(value)) {
2724                         /* Move the cursor. */
2725                         if (screen->origin_mode &&
2726                             screen->scrolling_restricted) {
2727                                 origin = screen->scrolling_region.start;
2728                         } else {
2729                                 origin = 0;
2730                         }
2731                         val = g_value_get_long(value) + origin;
2732                         val = CLAMP(val, 0, terminal->row_count - 1);
2733                         screen->cursor_current.row = screen->insert_delta + val;
2734                 }
2735         }
2736         return FALSE;
2737 }
2738
2739 /* Delete a character at the current cursor position. */
2740 static gboolean
2741 vte_sequence_handler_dc(VteTerminal *terminal,
2742                         const char *match,
2743                         GQuark match_quark,
2744                         GValueArray *params)
2745 {
2746         VteScreen *screen;
2747         VteRowData *rowdata;
2748         long col;
2749
2750         screen = terminal->pvt->screen;
2751
2752         if (_vte_ring_next(screen->row_data) > screen->cursor_current.row) {
2753                 /* Get the data for the row which the cursor points to. */
2754                 rowdata = _vte_ring_index(screen->row_data,
2755                                           VteRowData *,
2756                                           screen->cursor_current.row);
2757                 col = screen->cursor_current.col;
2758                 /* Remove the column. */
2759                 if (col < rowdata->cells->len) {
2760                         g_array_remove_index(rowdata->cells, col);
2761                 }
2762                 /* Add new cells until we have enough to fill the row. */
2763                 vte_g_array_fill(rowdata->cells,
2764                                  &screen->color_defaults,
2765                                  terminal->column_count);
2766                 /* Repaint this row. */
2767                 vte_invalidate_cells(terminal,
2768                                      0, terminal->column_count,
2769                                      screen->cursor_current.row, 1);
2770         }
2771
2772         /* We've modified the display.  Make a note of it. */
2773         terminal->pvt->text_deleted_count++;
2774         return FALSE;
2775 }
2776
2777 /* Delete N characters at the current cursor position. */
2778 static gboolean
2779 vte_sequence_handler_DC(VteTerminal *terminal,
2780                         const char *match,
2781                         GQuark match_quark,
2782                         GValueArray *params)
2783 {
2784         return vte_sequence_handler_multiple(terminal, match, match_quark,
2785                                              params, vte_sequence_handler_dc);
2786 }
2787
2788 /* Delete a line at the current cursor position. */
2789 static gboolean
2790 vte_sequence_handler_dl(VteTerminal *terminal,
2791                         const char *match,
2792                         GQuark match_quark,
2793                         GValueArray *params)
2794 {
2795         VteScreen *screen;
2796         long start, end, param, i;
2797         GValue *value;
2798
2799         /* Find out which part of the screen we're messing with. */
2800         screen = terminal->pvt->screen;
2801         start = screen->cursor_current.row;
2802         if (screen->scrolling_restricted) {
2803                 end = screen->insert_delta + screen->scrolling_region.end;
2804         } else {
2805                 end = screen->insert_delta + terminal->row_count - 1;
2806         }
2807
2808         /* Extract any parameters. */
2809         param = 1;
2810         if ((params != NULL) && (params->n_values > 0)) {
2811                 value = g_value_array_get_nth(params, 0);
2812                 param = g_value_get_long(value);
2813         }
2814
2815         /* Delete the right number of lines. */
2816         for (i = 0; i < param; i++) {
2817                 /* Clear a line off the end of the region and add one to the
2818                  * top of the region. */
2819                 vte_remove_line_internal(terminal, start);
2820                 vte_insert_line_internal(terminal, end);
2821                 /* Adjust the scrollbars if necessary. */
2822                 vte_terminal_adjust_adjustments(terminal, FALSE);
2823         }
2824
2825         /* Update the display. */
2826         vte_terminal_scroll_region(terminal, start, end - start + 1, -param);
2827
2828         /* We've modified the display.  Make a note of it. */
2829         terminal->pvt->text_deleted_count++;
2830         return FALSE;
2831 }
2832
2833 /* Delete N lines at the current cursor position. */
2834 static gboolean
2835 vte_sequence_handler_DL(VteTerminal *terminal,
2836                         const char *match,
2837                         GQuark match_quark,
2838                         GValueArray *params)
2839 {
2840         return vte_sequence_handler_dl(terminal, match, match_quark, params);
2841 }
2842
2843 /* Make sure we have enough rows and columns to hold data at the current
2844  * cursor position. */
2845 static void
2846 vte_terminal_ensure_cursor(VteTerminal *terminal, gboolean current)
2847 {
2848         VteRowData *row;
2849         VteScreen *screen;
2850         gboolean readjust = FALSE, fill = FALSE;
2851
2852         /* Must make sure we're in a sane area. */
2853         screen = terminal->pvt->screen;
2854
2855         /* Figure out how many rows we need to add. */
2856         fill = (terminal->pvt->screen->defaults.back != VTE_DEF_BG);
2857         while (screen->cursor_current.row >= _vte_ring_next(screen->row_data)) {
2858                 /* Create a new row. */
2859                 if (fill) {
2860                         row = vte_new_row_data_sized(terminal, TRUE);
2861                 } else {
2862                         row = vte_new_row_data(terminal);
2863                 }
2864                 _vte_ring_append(screen->row_data, row);
2865                 readjust = TRUE;
2866         }
2867         if (readjust) {
2868                 vte_terminal_adjust_adjustments(terminal, FALSE);
2869         }
2870
2871         /* Find the row the cursor is in. */
2872         row = _vte_ring_index(screen->row_data,
2873                               VteRowData *,
2874                               screen->cursor_current.row);
2875         if ((row->cells->len <= screen->cursor_current.col) &&
2876             (row->cells->len < terminal->column_count)) {
2877                 /* Set up defaults we'll use when adding new cells. */
2878                 if (current) {
2879                         /* Add new cells until we have one here. */
2880                         vte_g_array_fill(row->cells,
2881                                          &screen->color_defaults,
2882                                          screen->cursor_current.col + 1);
2883                 } else {
2884                         /* Add enough cells at the end to make sure we have
2885                          * enough for all visible columns. */
2886                         vte_g_array_fill(row->cells,
2887                                          &screen->basic_defaults,
2888                                          screen->cursor_current.col + 1);
2889                 }
2890         }
2891 }
2892
2893 /* Update the insert delta so that the screen which includes it also
2894  * includes the end of the buffer. */
2895 static void
2896 vte_terminal_update_insert_delta(VteTerminal *terminal)
2897 {
2898         long delta;
2899         VteScreen *screen;
2900
2901         screen = terminal->pvt->screen;
2902
2903         /* Make sure that the bottom row is visible, and that it's in
2904          * the buffer (even if it's empty).  This usually causes the
2905          * top row to become a history-only row. */
2906         delta = MAX(screen->insert_delta,
2907                     screen->cursor_current.row - (terminal->row_count - 1));
2908         delta = MAX(delta, _vte_ring_delta(screen->row_data));
2909
2910         /* Adjust the insert delta and scroll if needed. */
2911         if (delta != screen->insert_delta) {
2912                 vte_terminal_ensure_cursor(terminal, FALSE);
2913                 vte_terminal_adjust_adjustments(terminal, TRUE);
2914                 screen->insert_delta = delta;
2915         }
2916 }
2917
2918 /* Cursor down, no scrolling. */
2919 static gboolean
2920 vte_sequence_handler_do(VteTerminal *terminal,
2921                         const char *match,
2922                         GQuark match_quark,
2923                         GValueArray *params)
2924 {
2925         GtkWidget *widget;
2926         long start, end;
2927         VteScreen *screen;
2928
2929         widget = GTK_WIDGET(terminal);
2930         screen = terminal->pvt->screen;
2931
2932         if (screen->scrolling_restricted) {
2933                 start = screen->insert_delta + screen->scrolling_region.start;
2934                 end = screen->insert_delta + screen->scrolling_region.end;
2935         } else {
2936                 start = screen->insert_delta;
2937                 end = start + terminal->row_count - 1;
2938         }
2939
2940         /* Move the cursor down. */
2941         screen->cursor_current.row = MIN(screen->cursor_current.row + 1, end);
2942         return FALSE;
2943 }
2944
2945 /* Cursor down, no scrolling. */
2946 static gboolean
2947 vte_sequence_handler_DO(VteTerminal *terminal,
2948                         const char *match,
2949                         GQuark match_quark,
2950                         GValueArray *params)
2951 {
2952         return vte_sequence_handler_multiple(terminal, match, match_quark,
2953                                              params, vte_sequence_handler_do);
2954 }
2955
2956 /* Start using alternate character set. */
2957 static gboolean
2958 vte_sequence_handler_eA(VteTerminal *terminal,
2959                         const char *match,
2960                         GQuark match_quark,
2961                         GValueArray *params)
2962 {
2963         return vte_sequence_handler_ae(terminal, match, match_quark, params);
2964 }
2965
2966 /* Erase characters starting at the cursor position (overwriting N with
2967  * spaces, but not moving the cursor). */
2968 static gboolean
2969 vte_sequence_handler_ec(VteTerminal *terminal,
2970                         const char *match,
2971                         GQuark match_quark,
2972                         GValueArray *params)
2973 {
2974         VteScreen *screen;
2975         VteRowData *rowdata;
2976         GValue *value;
2977         struct vte_charcell *cell;
2978         long col, i, count;
2979
2980         screen = terminal->pvt->screen;
2981
2982         /* If we got a parameter, use it. */
2983         count = 1;
2984         if ((params != NULL) && (params->n_values > 0)) {
2985                 value = g_value_array_get_nth(params, 0);
2986                 if (G_VALUE_HOLDS_LONG(value)) {
2987                         count = g_value_get_long(value);
2988                 }
2989         }
2990
2991         /* Clear out the given number of characters. */
2992         vte_terminal_ensure_cursor(terminal, TRUE);
2993         if (_vte_ring_next(screen->row_data) > screen->cursor_current.row) {
2994                 /* Get the data for the row which the cursor points to. */
2995                 rowdata = _vte_ring_index(screen->row_data,
2996                                           VteRowData *,
2997                                           screen->cursor_current.row);
2998                 /* Write over the characters.  (If there aren't enough, we'll
2999                  * need to create them.) */
3000                 for (i = 0; i < count; i++) {
3001                         col = screen->cursor_current.col + i;
3002                         if (col >= 0) {
3003                                 if (col < rowdata->cells->len) {
3004                                         /* Replace this cell with the current
3005                                          * defaults. */
3006                                         cell = &g_array_index(rowdata->cells,
3007                                                               struct vte_charcell,
3008                                                               col);
3009                                         *cell = screen->color_defaults;
3010                                 } else {
3011                                         /* Add new cells until we have one here. */
3012                                         vte_g_array_fill(rowdata->cells,
3013                                                          &screen->color_defaults,
3014                                                          col);
3015                                 }
3016                         }
3017                 }
3018                 /* Repaint this row. */
3019                 vte_invalidate_cells(terminal,
3020                                      0, terminal->column_count,
3021                                      screen->cursor_current.row, 1);
3022         }
3023
3024         /* We've modified the display.  Make a note of it. */
3025         terminal->pvt->text_deleted_count++;
3026         return FALSE;
3027 }
3028
3029 /* End insert mode. */
3030 static gboolean
3031 vte_sequence_handler_ei(VteTerminal *terminal,
3032                         const char *match,
3033                         GQuark match_quark,
3034                         GValueArray *params)
3035 {
3036         terminal->pvt->screen->insert_mode = FALSE;
3037         return FALSE;
3038 }
3039
3040 /* Form-feed / next-page. */
3041 static gboolean
3042 vte_sequence_handler_form_feed(VteTerminal *terminal,
3043                                const char *match,
3044                                GQuark match_quark,
3045                                GValueArray *params)
3046 {
3047         return vte_sequence_handler_index(terminal, match, match_quark, params);
3048 }
3049
3050 /* Move from status line. */
3051 static gboolean
3052 vte_sequence_handler_fs(VteTerminal *terminal,
3053                         const char *match,
3054                         GQuark match_quark,
3055                         GValueArray *params)
3056 {
3057         terminal->pvt->screen->status_line = FALSE;
3058         return FALSE;
3059 }
3060
3061 /* Move the cursor to the home position. */
3062 static gboolean
3063 vte_sequence_handler_ho(VteTerminal *terminal,
3064                         const char *match,
3065                         GQuark match_quark,
3066                         GValueArray *params)
3067 {
3068         VteScreen *screen;
3069         screen = terminal->pvt->screen;
3070         screen->cursor_current.row = screen->insert_delta;
3071         screen->cursor_current.col = 0;
3072         return FALSE;
3073 }
3074
3075 /* Move the cursor to a specified position. */
3076 static gboolean
3077 vte_sequence_handler_horizontal_and_vertical_position(VteTerminal *terminal,
3078                                                       const char *match,
3079                                                       GQuark match_quark,
3080                                                       GValueArray *params)
3081 {
3082         return vte_sequence_handler_offset(terminal, match, match_quark, params,
3083                                            -1, vte_sequence_handler_cm);
3084 }
3085
3086 /* Insert a character. */
3087 static gboolean
3088 vte_sequence_handler_ic(VteTerminal *terminal,
3089                         const char *match,
3090                         GQuark match_quark,
3091                         GValueArray *params)
3092 {
3093         struct vte_cursor_position save;
3094         VteScreen *screen;
3095
3096         screen = terminal->pvt->screen;
3097
3098         save = screen->cursor_current;
3099
3100         vte_terminal_insert_char(terminal, ' ', TRUE, TRUE, TRUE, TRUE, 0);
3101
3102         screen->cursor_current = save;
3103
3104         return FALSE;
3105 }
3106
3107 /* Insert N characters. */
3108 static gboolean
3109 vte_sequence_handler_IC(VteTerminal *terminal,
3110                         const char *match,
3111                         GQuark match_quark,
3112                         GValueArray *params)
3113 {
3114         return vte_sequence_handler_multiple(terminal, match, match_quark,
3115                                              params, vte_sequence_handler_ic);
3116 }
3117
3118 /* Begin insert mode. */
3119 static gboolean
3120 vte_sequence_handler_im(VteTerminal *terminal,
3121                         const char *match,
3122                         GQuark match_quark,
3123                         GValueArray *params)
3124 {
3125         terminal->pvt->screen->insert_mode = TRUE;
3126         return FALSE;
3127 }
3128
3129 /* Cursor down, with scrolling. */
3130 static gboolean
3131 vte_sequence_handler_index(VteTerminal *terminal,
3132                            const char *match,
3133                            GQuark match_quark,
3134                            GValueArray *params)
3135 {
3136         return vte_sequence_handler_sf(terminal, match, match_quark, params);
3137 }
3138
3139 /* Send me a backspace key sym, will you?  Guess that the application meant
3140  * to send the cursor back one position. */
3141 static gboolean
3142 vte_sequence_handler_kb(VteTerminal *terminal,
3143                         const char *match,
3144                         GQuark match_quark,
3145                         GValueArray *params)
3146 {
3147         /* Move the cursor left. */
3148         return vte_sequence_handler_le(terminal, match, match_quark, params);
3149 }
3150
3151 /* Keypad mode end. */
3152 static gboolean
3153 vte_sequence_handler_ke(VteTerminal *terminal,
3154                         const char *match,
3155                         GQuark match_quark,
3156                         GValueArray *params)
3157 {
3158         terminal->pvt->keypad_mode = VTE_KEYMODE_NORMAL;
3159         return FALSE;
3160 }
3161
3162 /* Keypad mode start. */
3163 static gboolean
3164 vte_sequence_handler_ks(VteTerminal *terminal,
3165                         const char *match,
3166                         GQuark match_quark,
3167                         GValueArray *params)
3168 {
3169         terminal->pvt->keypad_mode = VTE_KEYMODE_APPLICATION;
3170         return FALSE;
3171 }
3172
3173 /* Cursor left. */
3174 static gboolean
3175 vte_sequence_handler_le(VteTerminal *terminal,
3176                         const char *match,
3177                         GQuark match_quark,
3178                         GValueArray *params)
3179 {
3180         VteScreen *screen;
3181
3182         screen = terminal->pvt->screen;
3183         if (screen->cursor_current.col > 0) {
3184                 /* There's room to move left, so do so. */
3185                 screen->cursor_current.col--;
3186         } else {
3187                 if (terminal->pvt->flags.bw) {
3188                         /* Wrap to the previous line. */
3189                         screen->cursor_current.col = terminal->column_count - 1;
3190                         screen->cursor_current.row = MAX(screen->cursor_current.row - 1,
3191                                                          screen->insert_delta);
3192                 } else {
3193                         /* Stick to the first column. */
3194                         screen->cursor_current.col = 0;
3195                 }
3196         }
3197         return FALSE;
3198 }
3199
3200 /* Move the cursor left N columns. */
3201 static gboolean
3202 vte_sequence_handler_LE(VteTerminal *terminal,
3203                         const char *match,
3204                         GQuark match_quark,
3205                         GValueArray *params)
3206 {
3207         return vte_sequence_handler_multiple(terminal, match, match_quark,
3208                                              params, vte_sequence_handler_le);
3209 }
3210
3211 /* Move the cursor to the lower left corner of the display. */
3212 static gboolean
3213 vte_sequence_handler_ll(VteTerminal *terminal,
3214                         const char *match,
3215                         GQuark match_quark,
3216                         GValueArray *params)
3217 {
3218         VteScreen *screen;
3219         screen = terminal->pvt->screen;
3220         screen->cursor_current.row = MAX(screen->insert_delta,
3221                                          screen->insert_delta +
3222                                          terminal->row_count - 1);
3223         screen->cursor_current.col = 0;
3224         return FALSE;
3225 }
3226
3227 /* Blink on. */
3228 static gboolean
3229 vte_sequence_handler_mb(VteTerminal *terminal,
3230                         const char *match,
3231                         GQuark match_quark,
3232                         GValueArray *params)
3233 {
3234         terminal->pvt->screen->defaults.blink = 1;
3235         return FALSE;
3236 }
3237
3238 /* Bold on. */
3239 static gboolean
3240 vte_sequence_handler_md(VteTerminal *terminal,
3241                         const char *match,
3242                         GQuark match_quark,
3243                         GValueArray *params)
3244 {
3245         terminal->pvt->screen->defaults.bold = 1;
3246         terminal->pvt->screen->defaults.half = 0;
3247         return FALSE;
3248 }
3249
3250 /* End modes. */
3251 static gboolean
3252 vte_sequence_handler_me(VteTerminal *terminal,
3253                         const char *match,
3254                         GQuark match_quark,
3255                         GValueArray *params)
3256 {
3257         vte_terminal_set_default_attributes(terminal);
3258         return FALSE;
3259 }
3260
3261 /* Half-bright on. */
3262 static gboolean
3263 vte_sequence_handler_mh(VteTerminal *terminal,
3264                         const char *match,
3265                         GQuark match_quark,
3266                         GValueArray *params)
3267 {
3268         terminal->pvt->screen->defaults.half = 1;
3269         terminal->pvt->screen->defaults.bold = 0;
3270         return FALSE;
3271 }
3272
3273 /* Invisible on. */
3274 static gboolean
3275 vte_sequence_handler_mk(VteTerminal *terminal,
3276                         const char *match,
3277                         GQuark match_quark,
3278                         GValueArray *params)
3279 {
3280         terminal->pvt->screen->defaults.invisible = 1;
3281         return FALSE;
3282 }
3283
3284 /* Protect on. */
3285 static gboolean
3286 vte_sequence_handler_mp(VteTerminal *terminal,
3287                         const char *match,
3288                         GQuark match_quark,
3289                         GValueArray *params)
3290 {
3291         terminal->pvt->screen->defaults.protect = 1;
3292         return FALSE;
3293 }
3294
3295 /* Reverse on. */
3296 static gboolean
3297 vte_sequence_handler_mr(VteTerminal *terminal,
3298                         const char *match,
3299                         GQuark match_quark,
3300                         GValueArray *params)
3301 {
3302         terminal->pvt->screen->defaults.reverse = 1;
3303         return FALSE;
3304 }
3305
3306 /* Cursor right. */
3307 static gboolean
3308 vte_sequence_handler_nd(VteTerminal *terminal,
3309                         const char *match,
3310                         GQuark match_quark,
3311                         GValueArray *params)
3312 {
3313         VteScreen *screen;
3314         screen = terminal->pvt->screen;
3315         if ((screen->cursor_current.col + 1) < terminal->column_count) {
3316                 /* There's room to move right. */
3317                 screen->cursor_current.col++;
3318         }
3319         return FALSE;
3320 }
3321
3322 /* Move the cursor to the beginning of the next line, scrolling if necessary. */
3323 static gboolean
3324 vte_sequence_handler_next_line(VteTerminal *terminal,
3325                                const char *match,
3326                                GQuark match_quark,
3327                                GValueArray *params)
3328 {
3329         terminal->pvt->screen->cursor_current.col = 0;
3330         return vte_sequence_handler_DO(terminal, match, match_quark, params);
3331 }
3332
3333 /* No-op. */
3334 static gboolean
3335 vte_sequence_handler_noop(VteTerminal *terminal,
3336                           const char *match,
3337                           GQuark match_quark,
3338                           GValueArray *params)
3339 {
3340         return FALSE;
3341 }
3342
3343 /* Carriage return command(?). */
3344 static gboolean
3345 vte_sequence_handler_nw(VteTerminal *terminal,
3346                         const char *match,
3347                         GQuark match_quark,
3348                         GValueArray *params)
3349 {
3350         return vte_sequence_handler_cr(terminal, match, match_quark, params);
3351 }
3352
3353 /* Restore cursor (position). */
3354 static gboolean
3355 vte_sequence_handler_rc(VteTerminal *terminal,
3356                         const char *match,
3357                         GQuark match_quark,
3358                         GValueArray *params)
3359 {
3360         VteScreen *screen;
3361         screen = terminal->pvt->screen;
3362         screen->cursor_current.col = screen->cursor_saved.col;
3363         screen->cursor_current.row = CLAMP(screen->cursor_saved.row +
3364                                            screen->insert_delta,
3365                                            screen->insert_delta,
3366                                            screen->insert_delta +
3367                                            terminal->row_count - 1);
3368         return FALSE;
3369 }
3370
3371 /* Cursor down, with scrolling. */
3372 static gboolean
3373 vte_sequence_handler_reverse_index(VteTerminal *terminal,
3374                                    const char *match,
3375                                    GQuark match_quark,
3376                                    GValueArray *params)
3377 {
3378         return vte_sequence_handler_sr(terminal, match, match_quark, params);
3379 }
3380
3381 /* Cursor right N characters. */
3382 static gboolean
3383 vte_sequence_handler_RI(VteTerminal *terminal,
3384                         const char *match,
3385                         GQuark match_quark,
3386                         GValueArray *params)
3387 {
3388         return vte_sequence_handler_multiple(terminal, match, match_quark,
3389                                              params, vte_sequence_handler_nd);
3390 }
3391
3392 /* Save cursor (position). */
3393 static gboolean
3394 vte_sequence_handler_sc(VteTerminal *terminal,
3395                         const char *match,
3396                         GQuark match_quark,
3397                         GValueArray *params)
3398 {
3399         VteScreen *screen;
3400         screen = terminal->pvt->screen;
3401         screen->cursor_saved.col = screen->cursor_current.col;
3402         screen->cursor_saved.row = CLAMP(screen->cursor_current.row -
3403                                          screen->insert_delta,
3404                                          0, terminal->row_count - 1);
3405         return FALSE;
3406 }
3407
3408 /* Standout end. */
3409 static gboolean
3410 vte_sequence_handler_se(VteTerminal *terminal,
3411                         const char *match,
3412                         GQuark match_quark,
3413                         GValueArray *params)
3414 {
3415         char *bold, *underline, *standout, *reverse, *half, *blink;
3416
3417         /* Standout may be mapped to another attribute, so attempt to do
3418          * the Right Thing here. */
3419         standout = _vte_termcap_find_string(terminal->pvt->termcap,
3420                                             terminal->pvt->emulation,
3421                                             "so");
3422         g_assert(standout != NULL);
3423         blink = _vte_termcap_find_string(terminal->pvt->termcap,
3424                                          terminal->pvt->emulation,
3425                                          "mb");
3426         bold = _vte_termcap_find_string(terminal->pvt->termcap,
3427                                         terminal->pvt->emulation,
3428                                         "md");
3429         half = _vte_termcap_find_string(terminal->pvt->termcap,
3430                                         terminal->pvt->emulation,
3431                                         "mh");
3432         reverse = _vte_termcap_find_string(terminal->pvt->termcap,
3433                                            terminal->pvt->emulation,
3434                                            "mr");
3435         underline = _vte_termcap_find_string(terminal->pvt->termcap,
3436                                              terminal->pvt->emulation,
3437                                              "us");
3438
3439         /* If the standout sequence is the same as another sequence, do what
3440          * we'd do for that other sequence instead. */
3441         if (blink && (g_ascii_strcasecmp(standout, blink) == 0)) {
3442                 vte_sequence_handler_me(terminal, match, match_quark, params);
3443         } else
3444         if (bold && (g_ascii_strcasecmp(standout, bold) == 0)) {
3445                 vte_sequence_handler_me(terminal, match, match_quark, params);
3446         } else
3447         if (half && (g_ascii_strcasecmp(standout, half) == 0)) {
3448                 vte_sequence_handler_me(terminal, match, match_quark, params);
3449         } else
3450         if (reverse && (g_ascii_strcasecmp(standout, reverse) == 0)) {
3451                 vte_sequence_handler_me(terminal, match, match_quark, params);
3452         } else
3453         if (underline && (g_ascii_strcasecmp(standout, underline) == 0)) {
3454                 vte_sequence_handler_ue(terminal, match, match_quark, params);
3455         } else {
3456                 /* Otherwise just set standout mode. */
3457                 terminal->pvt->screen->defaults.standout = 0;
3458         }
3459
3460         if (blink) {
3461                 g_free(blink);
3462         }
3463         if (bold) {
3464                 g_free(bold);
3465         }
3466         if (half) {
3467                 g_free(half);
3468         }
3469         if (reverse) {
3470                 g_free(reverse);
3471         }
3472         if (underline) {
3473                 g_free(underline);
3474         }
3475         g_free(standout);
3476         return FALSE;
3477 }
3478
3479 /* Cursor down, with scrolling. */
3480 static gboolean
3481 vte_sequence_handler_sf(VteTerminal *terminal,
3482                         const char *match,
3483                         GQuark match_quark,
3484                         GValueArray *params)
3485 {
3486         GtkWidget *widget;
3487         VteRowData *row;
3488         long start, end, top, bottom;
3489         VteScreen *screen;
3490
3491         widget = GTK_WIDGET(terminal);
3492         screen = terminal->pvt->screen;
3493
3494         if (screen->scrolling_restricted) {
3495                 start = screen->insert_delta + screen->scrolling_region.start;
3496                 end = screen->insert_delta + screen->scrolling_region.end;
3497         } else {
3498                 start = screen->insert_delta;
3499                 end = start + terminal->row_count - 1;
3500         }
3501
3502         if (screen->cursor_current.row == end) {
3503                 if (screen->scrolling_restricted) {
3504                         if (start == screen->insert_delta) {
3505                                 /* Scroll this line into the scrollback
3506                                  * buffer by inserting a line at the next
3507                                  * line and scrolling the area up. */
3508                                 row = vte_new_row_data_sized(terminal, TRUE);
3509                                 screen->insert_delta++;
3510                                 screen->scroll_delta++;
3511                                 screen->cursor_current.row++;
3512                                 _vte_ring_insert_preserve(terminal->pvt->screen->row_data,
3513