2 * Copyright (C) 2001,2002,2003 Red Hat, Inc.
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.
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.
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.
21 #include "../config.h"
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <sys/param.h>
44 #include <glib-object.h>
46 #include <gdk/gdkkeysyms.h>
48 #include <pango/pango.h>
60 #include "vteaccess.h"
66 #include <fontconfig/fontconfig.h>
73 typedef gunichar wint_t;
78 #define _(String) dgettext(PACKAGE, String)
80 #define _(String) String
81 #define bindtextdomain(package,dir)
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
93 #define VTE_BOLD_FG 26
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
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
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;
134 guint32 invisible: 1;
136 guint32 alternate: 1;
139 /* A match regex, with a tag. */
140 struct vte_match_regex {
141 struct _vte_regex *reg;
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 {
150 VTE_KEYMODE_APPLICATION
153 typedef struct _VteScreen VteScreen;
155 typedef struct _VteWordCharRange {
159 typedef struct _VteRowData {
161 guchar soft_wrapped: 1;
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 */
178 int keypad_mode, cursor_mode; /* these would be VteKeymodes, but we
179 need to guarantee its type */
180 gboolean sun_fkey_mode;
181 gboolean hp_fkey_mode;
182 gboolean legacy_fkey_mode;
183 gboolean vt220_fkey_mode;
184 int fkey; /* this would be a VteFKey, but we
185 need to guarantee its type */
186 GHashTable *dec_saved;
187 int default_column_count, default_row_count; /* default sizes */
189 /* PTY handling data. */
190 const char *shell; /* shell we started */
191 int pty_master; /* pty master descriptor */
192 GIOChannel *pty_input; /* master input watch */
193 guint pty_input_source;
194 GIOChannel *pty_output; /* master output watch */
195 guint pty_output_source;
196 pid_t pty_pid; /* pid of child using pty slave */
197 VteReaper *pty_reaper;
199 /* Input data queues. */
200 const char *encoding; /* the pty's encoding */
201 struct _vte_iso2022_state *iso2022;
202 struct _vte_buffer *incoming; /* pending bytestream */
203 GArray *pending; /* pending characters */
207 /* Output data queue. */
208 struct _vte_buffer *outgoing; /* pending input characters */
209 VteConv outgoing_conv;
212 struct _vte_buffer *conv_buffer;
214 /* Screen data. We support the normal screen, and an alternate
215 * screen, which seems to be a DEC-specific feature. */
217 VteRing *row_data; /* row data, arranged as a GArray of
218 vte_charcell structures */
219 struct vte_cursor_position {
221 } cursor_current, cursor_saved;
222 /* the current and saved positions of
223 the [insertion] cursor -- current is
224 absolute, saved is relative to the
226 gboolean reverse_mode; /* reverse mode */
227 gboolean origin_mode; /* origin mode */
228 gboolean sendrecv_mode; /* sendrecv mode */
229 gboolean insert_mode; /* insert mode */
230 gboolean linefeed_mode; /* linefeed mode */
231 struct vte_scrolling_region {
233 } scrolling_region; /* the region we scroll in */
234 gboolean scrolling_restricted;
235 long scroll_delta; /* scroll offset */
236 long insert_delta; /* insertion offset */
237 struct vte_charcell defaults; /* default characteristics
238 for insertion of any new
240 struct vte_charcell color_defaults; /* original defaults
243 struct vte_charcell fill_defaults; /* original defaults
247 struct vte_charcell basic_defaults; /* original defaults */
248 gboolean status_line;
249 GString *status_line_contents;
250 } normal_screen, alternate_screen, *screen;
252 /* Selection information. */
254 gboolean has_selection;
256 gboolean selecting_restart;
257 gboolean selecting_had_delta;
259 enum vte_selection_type {
264 struct selection_event_coords {
266 } selection_origin, selection_last, selection_restart_origin;
267 struct selection_cell_coords {
269 } selection_start, selection_end;
271 /* Miscellaneous options. */
272 VteTerminalEraseBinding backspace_binding, delete_binding;
273 gboolean meta_sends_escape;
274 gboolean audible_bell;
275 gboolean visible_bell;
276 gboolean margin_bell;
280 gboolean smooth_scroll;
281 GHashTable *tabstops;
282 gboolean text_modified_flag;
283 glong text_inserted_count;
284 glong text_deleted_count;
286 /* Scrolling options. */
287 gboolean scroll_background;
288 long scroll_lock_count;
289 gboolean scroll_on_output;
290 gboolean scroll_on_keystroke;
291 long scrollback_lines;
293 /* Cursor blinking. */
295 gboolean cursor_blinks;
296 gint cursor_blink_tag;
297 gint cursor_blink_timeout;
298 gboolean cursor_visible;
300 /* Input device options. */
301 time_t last_keypress_time;
302 gboolean mouse_send_xy_on_click;
303 gboolean mouse_send_xy_on_button;
304 gboolean mouse_hilite_tracking;
305 gboolean mouse_cell_motion_tracking;
306 gboolean mouse_all_motion_tracking;
307 guint mouse_last_button;
308 gdouble mouse_last_x, mouse_last_y;
309 gboolean mouse_autohide;
310 guint mouse_autoscroll_tag;
312 /* State variables for handling match checks. */
313 char *match_contents;
314 GArray *match_attributes;
315 GArray *match_regexes;
319 } match_start, match_end;
321 /* Data used when rendering the text which does not require server
322 * resources and which can be kept after unrealizing. */
323 PangoFontDescription *fontdesc;
324 GtkSettings *connected_settings;
326 /* Data used when rendering the text which reflects server resources
327 * and data, which should be dropped when unrealizing and (re)created
329 struct _vte_draw *draw;
331 gboolean palette_initialized;
332 gboolean highlight_color_set;
333 gboolean cursor_color_set;
334 struct vte_palette_entry {
335 guint16 red, green, blue;
336 } palette[VTE_CUR_BG + 1];
339 gboolean mouse_cursor_visible;
340 GdkCursor *mouse_default_cursor,
341 *mouse_mousing_cursor,
342 *mouse_inviso_cursor;
344 /* Input method support. */
345 GtkIMContext *im_context;
346 gboolean im_preedit_active;
348 PangoAttrList *im_preedit_attrs;
349 int im_preedit_cursor;
351 /* Our accessible peer. */
353 gboolean accessible_emit;
355 /* Adjustment updates pending. */
356 gboolean adjustment_changed_tag;
358 /* Background images/"transparency". */
359 gboolean bg_update_pending;
360 gboolean bg_transparent;
361 GdkPixbuf *bg_pixbuf;
364 GdkColor bg_tint_color;
365 long bg_saturation; /* out of VTE_SATURATION_MAX */
368 GdkModifierType modifiers;
370 /* Obscured? state. */
371 GdkVisibilityState visibility_state;
374 /* A function which can handle a terminal control sequence. Returns TRUE only
375 * if something happened (usually a signal emission) to which the controlling
376 * application must have an immediate opportunity to respond. */
377 typedef gboolean (*VteTerminalSequenceHandler)(VteTerminal *terminal,
380 GValueArray *params);
381 static void vte_terminal_set_termcap(VteTerminal *terminal, const char *path,
383 static void vte_terminal_ensure_cursor(VteTerminal *terminal, gboolean current);
384 static void vte_terminal_paste(VteTerminal *terminal, GdkAtom board);
385 static void vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
386 gboolean force_insert_mode,
387 gboolean invalidate_cells,
388 gboolean paint_cells,
389 gboolean ensure_after,
391 static gboolean vte_sequence_handler_clear_screen(VteTerminal *terminal,
394 GValueArray *params);
395 static gboolean vte_sequence_handler_do(VteTerminal *terminal,
398 GValueArray *params);
399 static gboolean vte_sequence_handler_DO(VteTerminal *terminal,
402 GValueArray *params);
403 static gboolean vte_sequence_handler_ho(VteTerminal *terminal,
406 GValueArray *params);
407 static gboolean vte_sequence_handler_index(VteTerminal *terminal,
410 GValueArray *params);
411 static gboolean vte_sequence_handler_le(VteTerminal *terminal,
414 GValueArray *params);
415 static gboolean vte_sequence_handler_LE(VteTerminal *terminal,
418 GValueArray *params);
419 static gboolean vte_sequence_handler_nd(VteTerminal *terminal,
422 GValueArray *params);
423 static gboolean vte_sequence_handler_sf(VteTerminal *terminal,
426 GValueArray *params);
427 static gboolean vte_sequence_handler_sr(VteTerminal *terminal,
430 GValueArray *params);
431 static gboolean vte_sequence_handler_ue(VteTerminal *terminal,
434 GValueArray *params);
435 static gboolean vte_sequence_handler_up(VteTerminal *terminal,
438 GValueArray *params);
439 static gboolean vte_sequence_handler_UP(VteTerminal *terminal,
442 GValueArray *params);
443 static gboolean vte_sequence_handler_us(VteTerminal *terminal,
446 GValueArray *params);
447 static gboolean vte_sequence_handler_vb(VteTerminal *terminal,
450 GValueArray *params);
451 static gboolean vte_terminal_io_read(GIOChannel *channel,
452 GdkInputCondition condition,
454 static gboolean vte_terminal_io_write(GIOChannel *channel,
455 GdkInputCondition condition,
457 static void vte_terminal_match_hilite_clear(VteTerminal *terminal);
458 static gboolean vte_terminal_background_update(gpointer data);
459 static void vte_terminal_queue_background_update(VteTerminal *terminal);
460 static void vte_terminal_queue_adjustment_changed(VteTerminal *terminal);
461 static gboolean vte_terminal_process_incoming(gpointer data);
462 static char *vte_terminal_get_text_range_maybe_wrapped(VteTerminal *terminal,
468 gboolean(*is_selected)(VteTerminal *,
474 static char *vte_terminal_get_text_maybe_wrapped(VteTerminal *terminal,
476 gboolean(*is_selected)(VteTerminal *,
482 static void _vte_terminal_disconnect_pty_read(VteTerminal *terminal);
483 static void _vte_terminal_disconnect_pty_write(VteTerminal *terminal);
485 /* Free a no-longer-used row data array. */
487 vte_free_row_data(gpointer freeing, gpointer data)
490 VteRowData *row = (VteRowData*) freeing;
491 g_array_free(row->cells, TRUE);
496 /* Append a single item to a GArray a given number of times. Centralizing all
497 * of the places we do this may let me do something more clever later. */
499 vte_g_array_fill(GArray *array, gpointer item, guint final_size)
501 g_assert(array != NULL);
502 if (array->len >= final_size) {
505 g_assert(item != NULL);
507 while (array->len < final_size) {
508 g_array_append_vals(array, item, 1);
512 /* Allocate a new line. */
514 vte_new_row_data(VteTerminal *terminal)
516 VteRowData *row = NULL;
517 row = g_malloc0(sizeof(VteRowData));
518 row->cells = g_array_new(FALSE, FALSE, sizeof(struct vte_charcell));
519 row->soft_wrapped = 0;
523 /* Allocate a new line of a given size. */
525 vte_new_row_data_sized(VteTerminal *terminal, gboolean fill)
527 VteRowData *row = NULL;
528 row = g_malloc0(sizeof(VteRowData));
529 row->cells = g_array_sized_new(FALSE, FALSE,
530 sizeof(struct vte_charcell),
531 terminal->column_count);
532 row->soft_wrapped = 0;
534 vte_g_array_fill(row->cells,
535 &terminal->pvt->screen->fill_defaults,
536 terminal->column_count);
541 /* Check how long a string of unichars is. Slow version. */
543 vte_unichar_strlen(gunichar *c)
546 for (i = 0; c[i] != 0; i++) ;
550 /* Reset defaults for character insertion. */
552 vte_terminal_set_default_attributes(VteTerminal *terminal)
554 g_return_if_fail(VTE_IS_TERMINAL(terminal));
555 terminal->pvt->screen->defaults.c = ' ';
556 terminal->pvt->screen->defaults.columns = 1;
557 terminal->pvt->screen->defaults.fragment = 0;
558 terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
559 terminal->pvt->screen->defaults.back = VTE_DEF_BG;
560 terminal->pvt->screen->defaults.reverse = 0;
561 terminal->pvt->screen->defaults.bold = 0;
562 terminal->pvt->screen->defaults.invisible = 0;
563 terminal->pvt->screen->defaults.protect = 0;
564 terminal->pvt->screen->defaults.standout = 0;
565 terminal->pvt->screen->defaults.underline = 0;
566 terminal->pvt->screen->defaults.strikethrough = 0;
567 terminal->pvt->screen->defaults.half = 0;
568 terminal->pvt->screen->defaults.blink = 0;
569 /* Alternate charset isn't an attribute, though we treat it as one.
570 * terminal->pvt->screen->defaults.alternate = 0; */
571 terminal->pvt->screen->basic_defaults = terminal->pvt->screen->defaults;
572 terminal->pvt->screen->color_defaults = terminal->pvt->screen->defaults;
573 terminal->pvt->screen->fill_defaults = terminal->pvt->screen->defaults;
576 /* Cause certain cells to be repainted. */
578 vte_invalidate_cells(VteTerminal *terminal,
579 glong column_start, gint column_count,
580 glong row_start, gint row_count)
585 g_return_if_fail(VTE_IS_TERMINAL(terminal));
586 widget = GTK_WIDGET(terminal);
587 if (!GTK_WIDGET_REALIZED(widget)) {
590 if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) {
594 /* Subtract the scrolling offset from the row start so that the
595 * resulting rectangle is relative to the visible portion of the
597 row_start -= terminal->pvt->screen->scroll_delta;
599 /* Clamp the start values to reasonable numbers. */
600 column_start = (column_start > 0) ? column_start : 0;
601 row_start = (row_start > 0) ? row_start : 0;
603 /* Convert the column and row start and end to pixel values
604 * by multiplying by the size of a character cell. */
605 rect.x = column_start * terminal->char_width + VTE_PAD_WIDTH;
606 rect.width = column_count * terminal->char_width;
607 if (column_start == 0) {
608 /* Include the left border. */
609 rect.x -= VTE_PAD_WIDTH;
610 rect.width += VTE_PAD_WIDTH;
612 if (column_start + column_count == terminal->column_count) {
613 /* Include the right border. */
614 rect.width += VTE_PAD_WIDTH;
617 rect.y = row_start * terminal->char_height + VTE_PAD_WIDTH;
618 rect.height = row_count * terminal->char_height;
620 /* Include the top border. */
621 rect.y -= VTE_PAD_WIDTH;
622 rect.height += VTE_PAD_WIDTH;
624 if (row_start + row_count == terminal->row_count) {
625 /* Include the bottom border. */
626 rect.height += VTE_PAD_WIDTH;
629 /* Invalidate the rectangle. */
630 gdk_window_invalidate_rect(widget->window, &rect, FALSE);
633 /* Redraw the entire visible portion of the window. */
635 vte_invalidate_all(VteTerminal *terminal)
641 g_return_if_fail(VTE_IS_TERMINAL(terminal));
642 if (!GTK_IS_WIDGET(terminal)) {
645 widget = GTK_WIDGET(terminal);
646 if (!GTK_WIDGET_REALIZED(widget)) {
649 if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) {
653 /* Expose the entire widget area. */
655 gdk_drawable_get_size(widget->window, &width, &height);
659 rect.height = height;
660 gdk_window_invalidate_rect(widget->window, &rect, FALSE);
663 /* Scroll a rectangular region up or down by a fixed number of lines. */
665 vte_terminal_scroll_region(VteTerminal *terminal,
666 long row, glong count, glong delta)
668 gboolean repaint = TRUE;
671 if ((delta == 0) || (count == 0)) {
676 /* We only do this if we're scrolling the entire window. */
677 if (!terminal->pvt->bg_transparent &&
678 (terminal->pvt->bg_pixbuf == NULL) &&
679 (terminal->pvt->bg_file == NULL) &&
680 (row == terminal->pvt->screen->scroll_delta) &&
681 (count == terminal->row_count) &&
682 (terminal->pvt->scroll_lock_count == 0)) {
683 height = terminal->char_height;
684 gdk_window_scroll((GTK_WIDGET(terminal))->window,
687 vte_invalidate_cells(terminal,
688 0, terminal->column_count,
691 vte_invalidate_cells(terminal,
692 0, terminal->column_count,
693 terminal->row_count + delta,
700 if (terminal->pvt->scroll_background) {
701 /* We have to repaint the entire window. */
702 vte_invalidate_all(terminal);
704 /* We have to repaint the area which is to be
706 vte_invalidate_cells(terminal,
707 0, terminal->column_count,
713 /* Find the character an the given position in the backscroll buffer. */
714 static struct vte_charcell *
715 vte_terminal_find_charcell(VteTerminal *terminal, glong col, glong row)
718 struct vte_charcell *ret = NULL;
720 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
721 screen = terminal->pvt->screen;
722 if (_vte_ring_contains(screen->row_data, row)) {
723 rowdata = _vte_ring_index(screen->row_data, VteRowData *, row);
724 if (rowdata->cells->len > col) {
725 ret = &g_array_index(rowdata->cells,
733 /* Determine the width of the portion of the preedit string which lies
734 * to the left of the cursor, or the entire string, in columns. */
736 vte_terminal_preedit_width(VteTerminal *terminal, gboolean left_only)
741 const char *preedit = NULL;
743 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), 0);
745 if (terminal->pvt->im_preedit != NULL) {
746 preedit = terminal->pvt->im_preedit;
749 (preedit[0] != '\0') &&
750 (!left_only || (i < terminal->pvt->im_preedit_cursor));
752 c = g_utf8_get_char(preedit);
753 ret += _vte_iso2022_unichar_width(c);
754 preedit = g_utf8_next_char(preedit);
761 /* Determine the length of the portion of the preedit string which lies
762 * to the left of the cursor, or the entire string, in gunichars. */
764 vte_terminal_preedit_length(VteTerminal *terminal, gboolean left_only)
768 const char *preedit = NULL;
770 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), 0);
772 if (terminal->pvt->im_preedit != NULL) {
773 preedit = terminal->pvt->im_preedit;
776 (preedit[0] != '\0') &&
777 (!left_only || (i < terminal->pvt->im_preedit_cursor));
779 c = g_utf8_get_char(preedit);
780 preedit = g_utf8_next_char(preedit);
787 /* Cause the cursor to be redrawn. */
789 vte_invalidate_cursor_once(gpointer data, gboolean periodic)
791 VteTerminal *terminal;
793 struct vte_charcell *cell;
794 gssize preedit_width;
795 int column, columns, row;
797 if (!VTE_IS_TERMINAL(data)) {
801 terminal = VTE_TERMINAL(data);
803 if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) {
808 if (!terminal->pvt->cursor_blinks) {
813 if (terminal->pvt->cursor_visible &&
814 GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
815 preedit_width = vte_terminal_preedit_width(terminal, FALSE);
817 screen = terminal->pvt->screen;
818 row = screen->cursor_current.row;
819 column = screen->cursor_current.col;
821 cell = vte_terminal_find_charcell(terminal,
823 screen->cursor_current.row);
824 while ((cell != NULL) && (cell->fragment) && (column > 0)) {
826 cell = vte_terminal_find_charcell(terminal,
831 columns = cell->columns;
832 if (_vte_draw_get_char_width(terminal->pvt->draw,
835 terminal->char_width * columns) {
839 if (preedit_width > 0) {
840 columns += preedit_width;
841 columns++; /* one more for the preedit cursor */
843 if (column + columns > terminal->column_count) {
844 column = MAX(0, terminal->column_count - columns);
847 vte_invalidate_cells(terminal,
851 if (_vte_debug_on(VTE_DEBUG_UPDATES)) {
852 fprintf(stderr, "Invalidating cursor at (%ld,%d-%d)."
853 "\n", screen->cursor_current.row,
861 /* Invalidate the cursor repeatedly. */
863 vte_invalidate_cursor_periodic(gpointer data)
865 VteTerminal *terminal;
867 GtkSettings *settings;
868 gint blink_cycle = 1000;
870 g_return_val_if_fail(VTE_IS_TERMINAL(data), FALSE);
871 widget = GTK_WIDGET(data);
872 if (!GTK_WIDGET_REALIZED(widget)) {
875 if (!GTK_WIDGET_HAS_FOCUS(widget)) {
879 terminal = VTE_TERMINAL(widget);
880 if (terminal->pvt->cursor_blinks) {
881 vte_invalidate_cursor_once(terminal, TRUE);
884 settings = gtk_widget_get_settings(GTK_WIDGET(data));
885 if (G_IS_OBJECT(settings)) {
886 g_object_get(G_OBJECT(settings), "gtk-cursor-blink-time",
890 if (terminal->pvt->cursor_blink_timeout != blink_cycle) {
891 terminal->pvt->cursor_blink_tag = g_timeout_add_full(G_PRIORITY_LOW,
893 vte_invalidate_cursor_periodic,
896 terminal->pvt->cursor_blink_timeout = blink_cycle;
903 /* Emit a "selection_changed" signal. */
905 vte_terminal_emit_selection_changed(VteTerminal *terminal)
908 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
909 fprintf(stderr, "Emitting `selection-changed'.\n");
912 g_signal_emit_by_name(terminal, "selection-changed");
915 /* Emit a "commit" signal. */
917 vte_terminal_emit_commit(VteTerminal *terminal, gchar *text, guint length)
919 char *wrapped = NULL;
921 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
922 fprintf(stderr, "Emitting `commit' of %d bytes.\n", length);
926 length = strlen(text);
929 wrapped = g_malloc0(length + 1);
930 memcpy(wrapped, text, length);
932 g_signal_emit_by_name(terminal, "commit", wrapped, length);
933 if (wrapped != text) {
938 /* Emit an "emulation-changed" signal. */
940 vte_terminal_emit_emulation_changed(VteTerminal *terminal)
943 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
944 fprintf(stderr, "Emitting `emulation-changed'.\n");
947 g_signal_emit_by_name(terminal, "emulation-changed");
950 /* Emit an "encoding-changed" signal. */
952 vte_terminal_emit_encoding_changed(VteTerminal *terminal)
955 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
956 fprintf(stderr, "Emitting `encoding-changed'.\n");
959 g_signal_emit_by_name(terminal, "encoding-changed");
962 /* Emit a "child-exited" signal. */
964 vte_terminal_emit_child_exited(VteTerminal *terminal)
967 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
968 fprintf(stderr, "Emitting `child-exited'.\n");
971 g_signal_emit_by_name(terminal, "child-exited");
974 /* Emit a "contents_changed" signal. */
976 vte_terminal_emit_contents_changed(VteTerminal *terminal)
979 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
980 fprintf(stderr, "Emitting `contents-changed'.\n");
983 g_signal_emit_by_name(terminal, "contents-changed");
986 /* Emit a "cursor_moved" signal. */
988 vte_terminal_emit_cursor_moved(VteTerminal *terminal)
991 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
992 fprintf(stderr, "Emitting `cursor-moved'.\n");
995 g_signal_emit_by_name(terminal, "cursor-moved");
998 /* Emit an "icon-title-changed" signal. */
1000 vte_terminal_emit_icon_title_changed(VteTerminal *terminal)
1003 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1004 fprintf(stderr, "Emitting `icon-title-changed'.\n");
1007 g_signal_emit_by_name(terminal, "icon-title-changed");
1010 /* Emit a "window-title-changed" signal. */
1012 vte_terminal_emit_window_title_changed(VteTerminal *terminal)
1015 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1016 fprintf(stderr, "Emitting `window-title-changed'.\n");
1019 g_signal_emit_by_name(terminal, "window-title-changed");
1022 /* Emit a "deiconify-window" signal. */
1024 vte_terminal_emit_deiconify_window(VteTerminal *terminal)
1027 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1028 fprintf(stderr, "Emitting `deiconify-window'.\n");
1031 g_signal_emit_by_name(terminal, "deiconify-window");
1034 /* Emit a "iconify-window" signal. */
1036 vte_terminal_emit_iconify_window(VteTerminal *terminal)
1039 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1040 fprintf(stderr, "Emitting `iconify-window'.\n");
1043 g_signal_emit_by_name(terminal, "iconify-window");
1046 /* Emit a "raise-window" signal. */
1048 vte_terminal_emit_raise_window(VteTerminal *terminal)
1051 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1052 fprintf(stderr, "Emitting `raise-window'.\n");
1055 g_signal_emit_by_name(terminal, "raise-window");
1058 /* Emit a "lower-window" signal. */
1060 vte_terminal_emit_lower_window(VteTerminal *terminal)
1063 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1064 fprintf(stderr, "Emitting `lower-window'.\n");
1067 g_signal_emit_by_name(terminal, "lower-window");
1070 /* Emit a "maximize-window" signal. */
1072 vte_terminal_emit_maximize_window(VteTerminal *terminal)
1075 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1076 fprintf(stderr, "Emitting `maximize-window'.\n");
1079 g_signal_emit_by_name(terminal, "maximize-window");
1082 /* Emit a "refresh-window" signal. */
1084 vte_terminal_emit_refresh_window(VteTerminal *terminal)
1087 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1088 fprintf(stderr, "Emitting `refresh-window'.\n");
1091 g_signal_emit_by_name(terminal, "refresh-window");
1094 /* Emit a "restore-window" signal. */
1096 vte_terminal_emit_restore_window(VteTerminal *terminal)
1099 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1100 fprintf(stderr, "Emitting `restore-window'.\n");
1103 g_signal_emit_by_name(terminal, "restore-window");
1106 /* Emit a "eof" signal. */
1108 vte_terminal_emit_eof(VteTerminal *terminal)
1111 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1112 fprintf(stderr, "Emitting `eof'.\n");
1115 g_signal_emit_by_name(terminal, "eof");
1118 /* Emit a "char-size-changed" signal. */
1120 vte_terminal_emit_char_size_changed(VteTerminal *terminal,
1121 guint width, guint height)
1124 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1125 fprintf(stderr, "Emitting `char-size-changed'.\n");
1128 g_signal_emit_by_name(terminal, "char-size-changed",
1132 /* Emit a "resize-window" signal. (Pixels.) */
1134 vte_terminal_emit_resize_window(VteTerminal *terminal,
1135 guint width, guint height)
1138 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1139 fprintf(stderr, "Emitting `resize-window'.\n");
1142 g_signal_emit_by_name(terminal, "resize-window", width, height);
1145 /* Emit a "move-window" signal. (Pixels.) */
1147 vte_terminal_emit_move_window(VteTerminal *terminal, guint x, guint y)
1150 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1151 fprintf(stderr, "Emitting `move-window'.\n");
1154 g_signal_emit_by_name(terminal, "move-window", x, y);
1157 /* Emit a "status-line-changed" signal. */
1159 vte_terminal_emit_status_line_changed(VteTerminal *terminal)
1162 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1163 fprintf(stderr, "Emitting `status-line-changed'.\n");
1166 g_signal_emit_by_name(terminal, "status-line-changed");
1169 /* Emit an "increase-font-size" signal. */
1171 vte_terminal_emit_increase_font_size(VteTerminal *terminal)
1174 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1175 fprintf(stderr, "Emitting `increase-font-size'.\n");
1178 g_signal_emit_by_name(terminal, "increase-font-size");
1181 /* Emit a "decrease-font-size" signal. */
1183 vte_terminal_emit_decrease_font_size(VteTerminal *terminal)
1186 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1187 fprintf(stderr, "Emitting `decrease-font-size'.\n");
1190 g_signal_emit_by_name(terminal, "decrease-font-size");
1193 /* Emit a "text-inserted" signal. */
1195 vte_terminal_emit_text_inserted(VteTerminal *terminal)
1197 if (!terminal->pvt->accessible_emit) {
1201 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1202 fprintf(stderr, "Emitting `text-inserted'.\n");
1205 g_signal_emit_by_name(terminal, "text-inserted");
1208 /* Emit a "text-deleted" signal. */
1210 vte_terminal_emit_text_deleted(VteTerminal *terminal)
1212 if (!terminal->pvt->accessible_emit) {
1216 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1217 fprintf(stderr, "Emitting `text-deleted'.\n");
1220 g_signal_emit_by_name(terminal, "text-deleted");
1223 /* Emit a "text-modified" signal. */
1225 vte_terminal_emit_text_modified(VteTerminal *terminal)
1227 if (!terminal->pvt->accessible_emit) {
1231 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1232 fprintf(stderr, "Emitting `text-modified'.\n");
1235 g_signal_emit_by_name(terminal, "text-modified");
1238 /* Emit a "text-scrolled" signal. */
1240 vte_terminal_emit_text_scrolled(VteTerminal *terminal, gint delta)
1242 if (!terminal->pvt->accessible_emit) {
1246 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1247 fprintf(stderr, "Emitting `text-scrolled'(%d).\n", delta);
1250 g_signal_emit_by_name(terminal, "text-scrolled", delta);
1253 /* Deselect anything which is selected and refresh the screen if needed. */
1255 vte_terminal_deselect_all(VteTerminal *terminal)
1257 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1258 if (terminal->pvt->has_selection) {
1259 terminal->pvt->has_selection = FALSE;
1261 if (_vte_debug_on(VTE_DEBUG_SELECTION)) {
1262 fprintf(stderr, "Deselecting all text.\n");
1265 vte_terminal_emit_selection_changed(terminal);
1266 vte_invalidate_all(terminal);
1270 /* Reset the set of tab stops to the default. */
1272 vte_terminal_set_tabstop(VteTerminal *terminal, int column)
1274 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1275 if (terminal->pvt->tabstops != NULL) {
1276 /* Just set a non-NULL pointer for this column number. */
1277 g_hash_table_insert(terminal->pvt->tabstops,
1278 GINT_TO_POINTER(2 * column + 1),
1283 /* Remove a tabstop. */
1285 vte_terminal_clear_tabstop(VteTerminal *terminal, int column)
1287 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1288 if (terminal->pvt->tabstops != NULL) {
1289 /* Remove a tab stop from the hash table. */
1290 g_hash_table_remove(terminal->pvt->tabstops,
1291 GINT_TO_POINTER(2 * column + 1));
1295 /* Check if we have a tabstop at a given position. */
1297 vte_terminal_get_tabstop(VteTerminal *terminal, int column)
1300 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
1301 if (terminal->pvt->tabstops != NULL) {
1302 hash = g_hash_table_lookup(terminal->pvt->tabstops,
1303 GINT_TO_POINTER(2 * column + 1));
1304 return (hash != NULL);
1310 /* Reset the set of tab stops to the default. */
1312 vte_terminal_set_default_tabstops(VteTerminal *terminal)
1315 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1316 if (terminal->pvt->tabstops != NULL) {
1317 g_hash_table_destroy(terminal->pvt->tabstops);
1319 terminal->pvt->tabstops = g_hash_table_new(g_direct_hash,
1321 width = _vte_termcap_find_numeric(terminal->pvt->termcap,
1322 terminal->pvt->emulation,
1325 width = VTE_TAB_WIDTH;
1327 for (i = 0; i <= VTE_TAB_MAX; i += width) {
1328 vte_terminal_set_tabstop(terminal, i);
1332 /* Clear the cache of the screen contents we keep. */
1334 vte_terminal_match_contents_clear(VteTerminal *terminal)
1336 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1337 if (terminal->pvt->match_contents != NULL) {
1338 g_free(terminal->pvt->match_contents);
1339 terminal->pvt->match_contents = NULL;;
1341 if (terminal->pvt->match_attributes != NULL) {
1342 g_array_free(terminal->pvt->match_attributes, TRUE);
1343 terminal->pvt->match_attributes = NULL;
1345 vte_terminal_match_hilite_clear(terminal);
1348 /* Refresh the cache of the screen contents we keep. */
1350 always_selected(VteTerminal *terminal, glong row, glong column, gpointer data)
1355 vte_terminal_match_contents_refresh(VteTerminal *terminal)
1358 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1359 vte_terminal_match_contents_clear(terminal);
1360 array = g_array_new(FALSE, TRUE, sizeof(struct _VteCharAttributes));
1361 terminal->pvt->match_contents = vte_terminal_get_text(terminal,
1365 terminal->pvt->match_attributes = array;
1369 * vte_terminal_match_clear_all:
1370 * @terminal: a #VteTerminal
1372 * Clears the list of regular expressions the terminal uses to highlight text
1373 * when the user moves the mouse cursor.
1377 vte_terminal_match_clear_all(VteTerminal *terminal)
1379 struct vte_match_regex *regex;
1381 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1382 for (i = 0; i < terminal->pvt->match_regexes->len; i++) {
1383 regex = &g_array_index(terminal->pvt->match_regexes,
1384 struct vte_match_regex,
1386 /* Unless this is a hole, clean it up. */
1387 if (regex->tag >= 0) {
1388 if (regex->cursor != NULL) {
1389 gdk_cursor_unref(regex->cursor);
1390 regex->cursor = NULL;
1392 _vte_regex_free(regex->reg);
1397 g_array_set_size(terminal->pvt->match_regexes, 0);
1398 vte_terminal_match_hilite_clear(terminal);
1402 * vte_terminal_match_remove:
1403 * @terminal: a #VteTerminal
1404 * @tag: the tag of the regex to remove
1406 * Removes the regular expression which is associated with the given @tag from
1407 * the list of expressions which the terminal will highlight when the user
1408 * moves the mouse cursor over matching text.
1412 vte_terminal_match_remove(VteTerminal *terminal, int tag)
1414 struct vte_match_regex *regex;
1415 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1416 if (terminal->pvt->match_regexes->len > tag) {
1417 /* The tag is an index, so find the corresponding struct. */
1418 regex = &g_array_index(terminal->pvt->match_regexes,
1419 struct vte_match_regex,
1421 /* If it's already been removed, return. */
1422 if (regex->tag < 0) {
1425 /* Remove this item and leave a hole in its place. */
1426 if (regex->cursor != NULL) {
1427 gdk_cursor_unref(regex->cursor);
1428 regex->cursor = NULL;
1430 _vte_regex_free(regex->reg);
1434 vte_terminal_match_hilite_clear(terminal);
1438 vte_terminal_cursor_new(VteTerminal *terminal, GdkCursorType cursor_type)
1440 #if GTK_CHECK_VERSION(2,2,0)
1441 GdkDisplay *display;
1444 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1446 display = gtk_widget_get_display(GTK_WIDGET(terminal));
1447 cursor = gdk_cursor_new_for_display(display, cursor_type);
1451 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1453 cursor = gdk_cursor_new(cursor_type);
1459 * vte_terminal_match_add:
1460 * @terminal: a #VteTerminal
1461 * @match: a regular expression
1463 * Adds a regular expression to the list of matching expressions. When the
1464 * user moves the mouse cursor over a section of displayed text which matches
1465 * this expression, the text will be highlighted.
1467 * Returns: an integer associated with this expression
1470 vte_terminal_match_add(VteTerminal *terminal, const char *match)
1472 struct vte_match_regex new_regex, *regex;
1474 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1);
1475 g_return_val_if_fail(match != NULL, -1);
1476 g_return_val_if_fail(strlen(match) > 0, -1);
1477 memset(&new_regex, 0, sizeof(new_regex));
1478 new_regex.reg = _vte_regex_compile(match);
1479 if (new_regex.reg == NULL) {
1480 g_warning(_("Error compiling regular expression \"%s\"."),
1485 /* Search for a hole. */
1486 for (ret = 0; ret < terminal->pvt->match_regexes->len; ret++) {
1487 regex = &g_array_index(terminal->pvt->match_regexes,
1488 struct vte_match_regex,
1490 if (regex->tag == -1) {
1494 /* Set the tag to the insertion point. */
1495 new_regex.tag = ret;
1496 new_regex.cursor = vte_terminal_cursor_new(terminal,
1497 VTE_DEFAULT_CURSOR);
1498 if (ret < terminal->pvt->match_regexes->len) {
1500 g_array_index(terminal->pvt->match_regexes,
1501 struct vte_match_regex,
1505 g_array_append_val(terminal->pvt->match_regexes, new_regex);
1507 return new_regex.tag;
1511 * vte_terminal_match_set_cursor:
1512 * @terminal: a #VteTerminal
1513 * @tag: the tag of the regex which should use the specified cursor
1514 * @cursor: the cursor which the terminal should use when the pattern is
1517 * Sets which cursor the terminal will use if the pointer is over the pattern
1518 * specified by @tag. The terminal keeps a reference to @cursor.
1524 vte_terminal_match_set_cursor(VteTerminal *terminal, int tag, GdkCursor *cursor)
1526 struct vte_match_regex *regex;
1527 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1528 g_return_if_fail(tag < terminal->pvt->match_regexes->len);
1529 regex = &g_array_index(terminal->pvt->match_regexes,
1530 struct vte_match_regex,
1532 if (regex->cursor != NULL) {
1533 gdk_cursor_unref(regex->cursor);
1535 regex->cursor = gdk_cursor_ref(cursor);
1536 vte_terminal_match_hilite_clear(terminal);
1540 * vte_terminal_match_set_cursor:
1541 * @terminal: a #VteTerminal
1542 * @tag: the tag of the regex which should use the specified cursor
1543 * @cursor: a #GdkCursorType
1545 * Sets which cursor the terminal will use if the pointer is over the pattern
1546 * specified by @tag. A convenience wrapper for
1547 * vte_terminal_match_set_cursor().
1553 vte_terminal_match_set_cursor_type(VteTerminal *terminal,
1554 int tag, GdkCursorType cursor_type)
1557 cursor = vte_terminal_cursor_new(terminal, cursor_type);
1558 vte_terminal_match_set_cursor(terminal, tag, cursor);
1559 gdk_cursor_unref(cursor);
1562 /* Check if a given cell on the screen contains part of a matched string. If
1563 * it does, return the string, and store the match tag in the optional tag
1566 vte_terminal_match_check_internal(VteTerminal *terminal,
1567 long column, glong row,
1568 int *tag, int *start, int *end)
1570 int i, j, ret, offset;
1571 struct vte_match_regex *regex = NULL;
1572 struct _VteCharAttributes *attr = NULL;
1574 struct _vte_regex_match matches[256];
1576 if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1577 fprintf(stderr, "Checking for match at (%ld,%ld).\n",
1584 if (start != NULL) {
1590 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1591 if (terminal->pvt->match_contents == NULL) {
1592 vte_terminal_match_contents_refresh(terminal);
1594 /* Map the pointer position to a portion of the string. */
1595 for (offset = terminal->pvt->match_attributes->len - 1;
1598 attr = &g_array_index(terminal->pvt->match_attributes,
1599 struct _VteCharAttributes,
1601 if ((row == attr->row) &&
1602 (column == attr->column) &&
1603 (terminal->pvt->match_contents[offset] != ' ')) {
1608 if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1610 fprintf(stderr, "Cursor is not on a character.\n");
1612 fprintf(stderr, "Cursor is on character %d.\n", offset);
1617 /* If the pointer isn't on a matchable character, bug out. */
1619 terminal->pvt->match_previous = -1;
1623 /* If the pointer is on a newline, bug out. */
1624 if ((g_ascii_isspace(terminal->pvt->match_contents[offset])) ||
1625 (terminal->pvt->match_contents[offset] == '\0')) {
1627 if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1628 fprintf(stderr, "Cursor is on whitespace.\n");
1631 terminal->pvt->match_previous = -1;
1635 /* Now iterate over each regex we need to match against. */
1636 for (i = 0; i < terminal->pvt->match_regexes->len; i++) {
1637 regex = &g_array_index(terminal->pvt->match_regexes,
1638 struct vte_match_regex,
1641 if (regex->tag < 0) {
1644 /* We'll only match the first item in the buffer which
1645 * matches, so we'll have to skip each match until we
1646 * stop getting matches. */
1648 ret = _vte_regex_exec(regex->reg,
1649 terminal->pvt->match_contents + coffset,
1650 G_N_ELEMENTS(matches),
1654 (j < G_N_ELEMENTS(matches)) &&
1655 (matches[j].rm_so != -1);
1657 /* The offsets should be "sane". */
1658 g_assert(matches[j].rm_so + coffset <
1659 terminal->pvt->match_attributes->len);
1660 g_assert(matches[j].rm_eo + coffset <=
1661 terminal->pvt->match_attributes->len);
1663 if (_vte_debug_on(VTE_DEBUG_MISC)) {
1665 struct _VteCharAttributes *sattr, *eattr;
1666 match = g_strndup(terminal->pvt->match_contents + matches[j].rm_so + coffset,
1667 matches[j].rm_eo - matches[j].rm_so);
1668 sattr = &g_array_index(terminal->pvt->match_attributes,
1669 struct _VteCharAttributes,
1670 matches[j].rm_so + coffset);
1671 eattr = &g_array_index(terminal->pvt->match_attributes,
1672 struct _VteCharAttributes,
1673 matches[j].rm_eo + coffset - 1);
1674 fprintf(stderr, "Match %d `%s' from %d(%ld,%ld) to %d(%ld,%ld) (%d).\n",
1676 matches[j].rm_so + coffset,
1679 matches[j].rm_eo + coffset - 1,
1687 /* Snip off any final newlines. */
1688 while ((matches[j].rm_eo > matches[j].rm_so) &&
1689 (terminal->pvt->match_contents[coffset + matches[j].rm_eo - 1] == '\n')) {
1692 /* If the pointer is in this substring,
1693 * then we're done. */
1694 if ((offset >= (matches[j].rm_so + coffset)) &&
1695 (offset < (matches[j].rm_eo + coffset))) {
1699 if (start != NULL) {
1705 matches[j].rm_eo - 1;
1707 if (GTK_WIDGET_REALIZED(GTK_WIDGET(terminal))) {
1708 gdk_window_set_cursor((GTK_WIDGET(terminal))->window,
1711 terminal->pvt->match_previous = regex->tag;
1712 return g_strndup(terminal->pvt->match_contents + coffset + matches[j].rm_so,
1713 matches[j].rm_eo - matches[j].rm_so);
1716 /* Skip past the beginning of this match to
1718 coffset += (matches[0].rm_so + 1);
1719 ret = _vte_regex_exec(regex->reg,
1720 terminal->pvt->match_contents +
1722 G_N_ELEMENTS(matches),
1726 terminal->pvt->match_previous = -1;
1731 * vte_terminal_match_check:
1732 * @terminal: a #VteTerminal
1733 * @column: the text column
1734 * @row: the text row
1735 * @tag: pointer to an integer
1737 * Checks if the text in and around the specified position matches any of the
1738 * regular expressions previously set using vte_terminal_match_add(). If a
1739 * match exists, the text string is returned and if @tag is not NULL, the number
1740 * associated with the matched regular expression will be stored in @tag.
1742 * If more than one regular expression has been set with
1743 * vte_terminal_match_add(), then expressions are checked in the order in
1744 * which they were added.
1746 * Returns: a string which matches one of the previously set regular
1747 * expressions, and which must be freed by the caller.
1750 vte_terminal_match_check(VteTerminal *terminal, glong column, glong row,
1755 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
1756 delta = terminal->pvt->screen->scroll_delta;
1758 if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1759 fprintf(stderr, "Checking for match at (%ld,%ld).\n",
1763 ret = vte_terminal_match_check_internal(terminal,
1764 column, row + delta,
1767 if ((ret != NULL) && _vte_debug_on(VTE_DEBUG_EVENTS)) {
1768 fprintf(stderr, "Matched `%s'.\n", ret);
1774 /* Emit an adjustment changed signal on our adjustment object. */
1776 vte_terminal_emit_adjustment_changed(gpointer data)
1778 VteTerminal *terminal;
1779 terminal = VTE_TERMINAL(data);
1780 if (terminal->pvt->adjustment_changed_tag) {
1782 if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
1783 fprintf(stderr, "Emitting adjustment_changed.\n");
1786 terminal->pvt->adjustment_changed_tag = 0;
1787 gtk_adjustment_changed(terminal->adjustment);
1792 /* Queue an adjustment-changed signal to be delivered when convenient. */
1794 vte_terminal_queue_adjustment_changed(VteTerminal *terminal)
1796 if (terminal->pvt->adjustment_changed_tag == 0) {
1797 terminal->pvt->adjustment_changed_tag =
1798 g_idle_add_full(VTE_ADJUSTMENT_PRIORITY,
1799 vte_terminal_emit_adjustment_changed,
1804 if (_vte_debug_on(VTE_DEBUG_EVENTS)) {
1805 fprintf(stderr, "Swallowing duplicate "
1806 "adjustment-changed signal.\n");
1812 /* Update the adjustment field of the widget. This function should be called
1813 * whenever we add rows to or remove rows from the history or switch screens. */
1815 vte_terminal_adjust_adjustments(VteTerminal *terminal, gboolean immediate)
1822 g_return_if_fail(terminal->pvt->screen != NULL);
1823 g_return_if_fail(terminal->pvt->screen->row_data != NULL);
1825 /* Adjust the vertical, uh, adjustment. */
1828 /* The lower value should be the first row in the buffer. */
1829 screen = terminal->pvt->screen;
1830 delta = _vte_ring_delta(screen->row_data);
1832 if (_vte_debug_on(VTE_DEBUG_IO)) {
1833 fprintf(stderr, "Changing adjustment values "
1834 "(delta = %ld, scroll = %ld).\n",
1835 delta, screen->scroll_delta);
1838 if (terminal->adjustment->lower != delta) {
1839 terminal->adjustment->lower = delta;
1843 /* Snap the insert delta and the cursor position to be in the visible
1844 * area. Leave the scrolling delta alone because it will be updated
1845 * when the adjustment changes. */
1846 screen->insert_delta = MAX(screen->insert_delta, delta);
1847 screen->cursor_current.row = MAX(screen->cursor_current.row,
1848 screen->insert_delta);
1850 /* The upper value is the number of rows which might be visible. (Add
1851 * one to the cursor offset because it's zero-based.) */
1852 rows = MAX(_vte_ring_next(terminal->pvt->screen->row_data),
1853 terminal->pvt->screen->cursor_current.row + 1);
1854 if (terminal->adjustment->upper != rows) {
1855 terminal->adjustment->upper = rows;
1859 /* The step increment should always be one. */
1860 if (terminal->adjustment->step_increment != 1) {
1861 terminal->adjustment->step_increment = 1;
1865 /* Set the number of rows the user sees to the number of rows the
1867 if (terminal->adjustment->page_size != terminal->row_count) {
1868 terminal->adjustment->page_size = terminal->row_count;
1872 /* Clicking in the empty area should scroll one screen, so set the
1873 * page size to the number of visible rows. */
1874 if (terminal->adjustment->page_increment != terminal->row_count) {
1875 terminal->adjustment->page_increment = terminal->row_count;
1879 /* Set the scrollbar adjustment to where the screen wants it to be. */
1880 if (floor(terminal->adjustment->value) !=
1881 terminal->pvt->screen->scroll_delta) {
1882 /* This emits a "value-changed" signal, so no need to screw
1883 * with anything else for just this. */
1884 gtk_adjustment_set_value(terminal->adjustment,
1885 terminal->pvt->screen->scroll_delta);
1888 /* If anything changed, signal that there was a change. */
1889 if (changed == TRUE) {
1891 if (_vte_debug_on(VTE_DEBUG_IO)) {
1892 fprintf(stderr, "Changed adjustment values "
1893 "(delta = %ld, scroll = %ld).\n",
1894 delta, terminal->pvt->screen->scroll_delta);
1898 gtk_adjustment_changed(terminal->adjustment);
1900 vte_terminal_queue_adjustment_changed(terminal);
1905 /* Scroll up or down in the current screen. */
1907 vte_terminal_scroll_pages(VteTerminal *terminal, gint pages)
1910 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1912 if (_vte_debug_on(VTE_DEBUG_IO)) {
1913 fprintf(stderr, "Scrolling %d pages.\n", pages);
1916 /* Calculate the ideal position where we want to be before clamping. */
1917 destination = floor(gtk_adjustment_get_value(terminal->adjustment));
1918 destination += (pages * terminal->row_count);
1919 /* Can't scroll past data we have. */
1920 destination = CLAMP(destination,
1921 terminal->adjustment->lower,
1922 terminal->adjustment->upper - terminal->row_count);
1923 /* Tell the scrollbar to adjust itself. */
1924 gtk_adjustment_set_value(terminal->adjustment, destination);
1925 /* Clear dingus match set. */
1926 vte_terminal_match_contents_clear(terminal);
1927 /* Notify viewers that the contents have changed. */
1928 vte_terminal_emit_contents_changed(terminal);
1931 /* Scroll so that the scroll delta is the minimum value. */
1933 vte_terminal_maybe_scroll_to_top(VteTerminal *terminal)
1936 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1937 if (floor(gtk_adjustment_get_value(terminal->adjustment)) !=
1938 _vte_ring_delta(terminal->pvt->screen->row_data)) {
1939 delta = _vte_ring_delta(terminal->pvt->screen->row_data);
1940 gtk_adjustment_set_value(terminal->adjustment, delta);
1944 /* Scroll so that the scroll delta is the insertion delta. */
1946 vte_terminal_maybe_scroll_to_bottom(VteTerminal *terminal)
1949 g_return_if_fail(VTE_IS_TERMINAL(terminal));
1950 if (floor(gtk_adjustment_get_value(terminal->adjustment)) !=
1951 terminal->pvt->screen->insert_delta) {
1952 delta = terminal->pvt->screen->insert_delta;
1953 gtk_adjustment_set_value(terminal->adjustment, delta);
1957 /* Call another function, offsetting any long arguments by the given
1958 * increment value. */
1960 vte_sequence_handler_offset(VteTerminal *terminal,
1963 GValueArray *params,
1965 VteTerminalSequenceHandler handler)
1970 /* Decrement the parameters and let the _cs handler deal with it. */
1971 for (i = 0; (params != NULL) && (i < params->n_values); i++) {
1972 value = g_value_array_get_nth(params, i);
1973 if (G_VALUE_HOLDS_LONG(value)) {
1974 val = g_value_get_long(value);
1976 g_value_set_long(value, val);
1979 return handler(terminal, match, match_quark, params);
1982 /* Call another function a given number of times, or once. */
1984 vte_sequence_handler_multiple(VteTerminal *terminal,
1987 GValueArray *params,
1988 VteTerminalSequenceHandler handler)
1994 if ((params != NULL) && (params->n_values > 0)) {
1995 value = g_value_array_get_nth(params, 0);
1996 if (G_VALUE_HOLDS_LONG(value)) {
1997 val = g_value_get_long(value);
1998 val = MAX(val, 1); /* FIXME: vttest. */
2002 for (i = 0; i < val; i++) {
2003 if (handler(terminal, match, match_quark, NULL)) {
2010 /* Insert a blank line at an arbitrary position. */
2012 vte_insert_line_internal(VteTerminal *terminal, glong position)
2015 /* Pad out the line data to the insertion point. */
2016 while (_vte_ring_next(terminal->pvt->screen->row_data) < position) {
2017 row = vte_new_row_data_sized(terminal, TRUE);
2018 _vte_ring_append(terminal->pvt->screen->row_data, row);
2020 /* If we haven't inserted a line yet, insert a new one. */
2021 row = vte_new_row_data_sized(terminal, TRUE);
2022 if (_vte_ring_next(terminal->pvt->screen->row_data) >= position) {
2023 _vte_ring_insert(terminal->pvt->screen->row_data,
2026 _vte_ring_append(terminal->pvt->screen->row_data, row);
2030 /* Remove a line at an arbitrary position. */
2032 vte_remove_line_internal(VteTerminal *terminal, glong position)
2034 if (_vte_ring_next(terminal->pvt->screen->row_data) > position) {
2035 _vte_ring_remove(terminal->pvt->screen->row_data,
2041 * vte_terminal_set_encoding:
2042 * @terminal: a #VteTerminal
2043 * @codeset: a valid #g_iconv target
2045 * Changes the encoding the terminal will expect data from the child to
2046 * be encoded with. For certain terminal types, applications executing in the
2047 * terminal can change the encoding. The default encoding is defined by the
2048 * application's locale settings.
2052 vte_terminal_set_encoding(VteTerminal *terminal, const char *codeset)
2054 const char *old_codeset;
2055 GQuark encoding_quark;
2057 char *obuf1, *obuf2;
2058 gsize bytes_written;
2060 old_codeset = terminal->pvt->encoding;
2061 if (codeset == NULL) {
2062 g_get_charset(&codeset);
2064 if ((old_codeset != NULL) && (strcmp(codeset, old_codeset) == 0)) {
2065 /* Nothing to do! */
2069 /* Open new conversions. */
2070 conv = _vte_conv_open(codeset, "UTF-8");
2071 if (conv == ((VteConv) -1)) {
2072 g_warning(_("Unable to convert characters from %s to %s."),
2076 if (terminal->pvt->outgoing_conv != (VteConv) -1) {
2077 _vte_conv_close(terminal->pvt->outgoing_conv);
2079 terminal->pvt->outgoing_conv = conv;
2081 /* Set the terminal's encoding to the new value. */
2082 encoding_quark = g_quark_from_string(codeset);
2083 terminal->pvt->encoding = g_quark_to_string(encoding_quark);
2085 /* Convert any buffered output bytes. */
2086 if ((_vte_buffer_length(terminal->pvt->outgoing) > 0) &&
2087 (old_codeset != NULL)) {
2088 /* Convert back to UTF-8. */
2089 obuf1 = g_convert(terminal->pvt->outgoing->bytes,
2090 _vte_buffer_length(terminal->pvt->outgoing),
2096 if (obuf1 != NULL) {
2097 /* Convert to the new encoding. */
2098 obuf2 = g_convert(obuf1,
2105 if (obuf2 != NULL) {
2106 _vte_buffer_clear(terminal->pvt->outgoing);
2107 _vte_buffer_append(terminal->pvt->outgoing,
2108 obuf2, bytes_written);
2115 /* Set the encoding for incoming text. */
2116 _vte_iso2022_state_set_codeset(terminal->pvt->iso2022,
2117 terminal->pvt->encoding);
2120 if (_vte_debug_on(VTE_DEBUG_IO)) {
2121 fprintf(stderr, "Set terminal encoding to `%s'.\n",
2122 terminal->pvt->encoding);
2125 vte_terminal_emit_encoding_changed(terminal);
2129 * vte_terminal_get_encoding:
2130 * @terminal: a #VteTerminal
2132 * Determines the name of the encoding in which the terminal expects data to be
2135 * Returns: the current encoding for the terminal.
2138 vte_terminal_get_encoding(VteTerminal *terminal)
2140 g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
2141 return terminal->pvt->encoding;
2144 /* End alternate character set. */
2146 vte_sequence_handler_ae(VteTerminal *terminal,
2149 GValueArray *params)
2151 terminal->pvt->screen->defaults.alternate = 0;
2155 /* Add a line at the current cursor position. */
2157 vte_sequence_handler_al(VteTerminal *terminal,
2160 GValueArray *params)
2163 VteRowData *rowdata;
2164 long start, end, param, i;
2167 /* Find out which part of the screen we're messing with. */
2168 screen = terminal->pvt->screen;
2169 start = screen->cursor_current.row;
2170 if (screen->scrolling_restricted) {
2171 end = screen->insert_delta + screen->scrolling_region.end;
2173 end = screen->insert_delta + terminal->row_count - 1;
2176 /* Extract any parameters. */
2178 if ((params != NULL) && (params->n_values > 0)) {
2179 value = g_value_array_get_nth(params, 0);
2180 param = g_value_get_long(value);
2183 /* Insert the right number of lines. */
2184 for (i = 0; i < param; i++) {
2185 /* Clear a line off the end of the region and add one to the
2186 * top of the region. */
2187 vte_remove_line_internal(terminal, end);
2188 vte_insert_line_internal(terminal, start);
2189 /* Get the data for the new row. */
2190 rowdata = _vte_ring_index(screen->row_data,
2191 VteRowData *, start);
2192 /* Add enough cells to it so that it has the default colors. */
2193 vte_g_array_fill(rowdata->cells, &screen->fill_defaults,
2194 terminal->column_count);
2195 /* Adjust the scrollbars if necessary. */
2196 vte_terminal_adjust_adjustments(terminal, FALSE);
2199 /* Update the display. */
2200 vte_terminal_scroll_region(terminal, start, end - start + 1, param);
2202 /* We've modified the display. Make a note of it. */
2203 terminal->pvt->text_deleted_count++;
2207 /* Add N lines at the current cursor position. */
2209 vte_sequence_handler_AL(VteTerminal *terminal,
2212 GValueArray *params)
2214 return vte_sequence_handler_al(terminal, match, match_quark, params);
2217 /* Start using alternate character set. */
2219 vte_sequence_handler_as(VteTerminal *terminal,
2222 GValueArray *params)
2224 terminal->pvt->screen->defaults.alternate = 1;
2229 vte_terminal_beep(VteTerminal *terminal)
2231 #if GTK_CHECK_VERSION(2,2,0)
2232 GdkDisplay *display;
2234 g_return_if_fail(VTE_IS_TERMINAL(terminal));
2235 display = gtk_widget_get_display(GTK_WIDGET(terminal));
2236 gdk_display_beep(display);
2244 vte_sequence_handler_bl(VteTerminal *terminal,
2247 GValueArray *params)
2249 if (terminal->pvt->audible_bell) {
2251 vte_terminal_beep(terminal);
2253 if (terminal->pvt->visible_bell) {
2255 vte_sequence_handler_vb(terminal, match, match_quark, params);
2262 vte_sequence_handler_bt(VteTerminal *terminal,
2265 GValueArray *params)
2269 /* Calculate which column is the previous tab stop. */
2270 newcol = terminal->pvt->screen->cursor_current.col;
2272 if (terminal->pvt->tabstops != NULL) {
2273 /* Find the next tabstop. */
2274 while (newcol >= 0) {
2275 if (vte_terminal_get_tabstop(terminal,
2276 newcol % terminal->column_count)) {
2283 /* If we have no tab stops, stop at the first column. */
2288 /* Warp the cursor. */
2290 if (_vte_debug_on(VTE_DEBUG_PARSE)) {
2291 fprintf(stderr, "Moving cursor to column %ld.\n", (long)newcol);
2294 terminal->pvt->screen->cursor_current.col = newcol;
2298 /* Clear from the cursor position to the beginning of the line. */
2300 vte_sequence_handler_cb(VteTerminal *terminal,
2303 GValueArray *params)
2305 VteRowData *rowdata;
2308 struct vte_charcell *pcell;
2309 screen = terminal->pvt->screen;
2311 /* Get the data for the row which the cursor points to. */
2312 vte_terminal_ensure_cursor(terminal, FALSE);
2313 rowdata = _vte_ring_index(screen->row_data,
2315 screen->cursor_current.row);
2316 /* Clear the data up to the current column with the default
2317 * attributes. If there is no such character cell, we need
2319 for (i = 0; i <= screen->cursor_current.col; i++) {
2320 if (i < rowdata->cells->len) {
2321 /* Muck with the cell in this location. */
2322 pcell = &g_array_index(rowdata->cells,
2323 struct vte_charcell,
2325 *pcell = screen->color_defaults;
2327 /* Add new cells until we have one here. */
2328 g_array_append_val(rowdata->cells,
2329 screen->color_defaults);
2332 /* Repaint this row. */
2333 vte_invalidate_cells(terminal,
2334 0, terminal->column_count,
2335 screen->cursor_current.row, 1);
2337 /* We've modified the display. Make a note of it. */
2338 terminal->pvt->text_deleted_count++;
2342 /* Clear to the right of the cursor and below the current line. */
2344 vte_sequence_handler_cd(VteTerminal *terminal,
2347 GValueArray *params)
2349 VteRowData *rowdata;
2353 screen = terminal->pvt->screen;
2354 /* If the cursor is actually on the screen, clear the rest of the
2355 * row the cursor is on and all of the rows below the cursor. */
2356 i = screen->cursor_current.row;
2357 if (i < _vte_ring_next(screen->row_data)) {
2358 /* Get the data for the row we're clipping. */
2359 rowdata = _vte_ring_index(screen->row_data, VteRowData *, i);
2360 /* Clear everything to the right of the cursor. */
2361 if ((rowdata != NULL) &&
2362 (rowdata->cells->len > screen->cursor_current.col)) {
2363 g_array_set_size(rowdata->cells,
2364 screen->cursor_current.col);
2367 /* Now for the rest of the lines. */
2368 for (i = screen->cursor_current.row + 1;
2369 i < _vte_ring_next(screen->row_data);
2371 /* Get the data for the row we're removing. */
2372 rowdata = _vte_ring_index(screen->row_data, VteRowData *, i);
2374 if ((rowdata != NULL) && (rowdata->cells->len > 0)) {
2375 g_array_set_size(rowdata->cells, 0);
2378 /* Now fill the cleared areas. */
2379 for (i = screen->cursor_current.row;
2380 i < screen->insert_delta + terminal->row_count;
2382 /* Retrieve the row's data, creating it if necessary. */
2383 if (_vte_ring_contains(screen->row_data, i)) {
2384 rowdata = _vte_ring_index(screen->row_data,
2387 rowdata = vte_new_row_data(terminal);
2388 _vte_ring_append(screen->row_data, rowdata);
2390 /* Pad out the row. */
2391 vte_g_array_fill(rowdata->cells,
2392 &screen->fill_defaults,
2393 terminal->column_count);
2394 /* Repaint this row. */
2395 vte_invalidate_cells(terminal,
2396 0, terminal->column_count,
2400 /* We've modified the display. Make a note of it. */
2401 terminal->pvt->text_deleted_count++;
2405 /* Clear from the cursor position to the end of the line. */
2407 vte_sequence_handler_ce(VteTerminal *terminal,
2410 GValueArray *params)
2412 VteRowData *rowdata;
2415 screen = terminal->pvt->screen;
2416 /* Get the data for the row which the cursor points to. */
2417 vte_terminal_ensure_cursor(terminal, FALSE);
2418 rowdata = _vte_ring_index(screen->row_data, VteRowData *,
2419 screen->cursor_current.row);
2420 /* Remove the data at the end of the array until the current column
2421 * is the end of the array. */
2422 if (rowdata->cells->len > screen->cursor_current.col) {
2423 g_array_set_size(rowdata->cells, screen->cursor_current.col);
2425 /* Add enough cells to the end of the line to fill out the row. */
2426 vte_g_array_fill(rowdata->cells,
2427 &screen->fill_defaults,
2428 terminal->column_count);
2429 /* Repaint this row. */
2430 vte_invalidate_cells(terminal,
2431 0, terminal->column_count,
2432 screen->cursor_current.row, 1);
2434 /* We've modified the display. Make a note of it. */
2435 terminal->pvt->text_deleted_count++;
2439 /* Move the cursor to the given column (horizontal position). */
2441 vte_sequence_handler_ch(VteTerminal *terminal,
2444 GValueArray *params)
2450 screen = terminal->pvt->screen;
2451 /* We only care if there's a parameter in there. */
2452 if ((params != NULL) && (params->n_values > 0)) {
2453 value = g_value_array_get_nth(params, 0);
2454 if (G_VALUE_HOLDS_LONG(value)) {
2455 val = CLAMP(g_value_get_long(value),
2457 terminal->column_count - 1);
2458 /* Move the cursor. */
2459 screen->cursor_current.col = val;
2465 /* Clear the screen and home the cursor. */
2467 vte_sequence_handler_cl(VteTerminal *terminal,
2470 GValueArray *params)
2472 vte_sequence_handler_clear_screen(terminal, NULL, 0, NULL);
2473 vte_sequence_handler_ho(terminal, NULL, 0, NULL);
2475 /* We've modified the display. Make a note of it. */
2476 terminal->pvt->text_deleted_count++;
2480 /* Move the cursor to the given position. */
2482 vte_sequence_handler_cm(VteTerminal *terminal,
2485 GValueArray *params)
2488 long rowval, colval, origin;
2491 screen = terminal->pvt->screen;
2492 /* We need at least two parameters. */
2493 if ((params != NULL) && (params->n_values >= 2)) {
2494 /* The first is the row, the second is the column. */
2495 row = g_value_array_get_nth(params, 0);
2496 col = g_value_array_get_nth(params, 1);
2497 if (G_VALUE_HOLDS_LONG(row) &&
2498 G_VALUE_HOLDS_LONG(col)) {
2499 if (screen->origin_mode &&
2500 screen->scrolling_restricted) {
2501 origin = screen->scrolling_region.start;
2505 rowval = g_value_get_long(row) + origin;
2506 colval = g_value_get_long(col);
2507 rowval = CLAMP(rowval, 0, terminal->row_count - 1);
2508 colval = CLAMP(colval, 0, terminal->column_count - 1);
2509 screen->cursor_current.row = rowval +
2510 screen->insert_delta;
2511 screen->cursor_current.col = colval;
2517 /* Clear the current line. */
2519 vte_sequence_handler_clear_current_line(VteTerminal *terminal,
2522 GValueArray *params)
2524 VteRowData *rowdata;
2527 screen = terminal->pvt->screen;
2529 /* If the cursor is actually on the screen, clear data in the row
2530 * which corresponds to the cursor. */
2531 if (_vte_ring_next(screen->row_data) > screen->cursor_current.row) {
2532 /* Get the data for the row which the cursor points to. */
2533 rowdata = _vte_ring_index(screen->row_data, VteRowData *,
2534 screen->cursor_current.row);
2536 if (rowdata->cells->len > 0) {
2537 g_array_set_size(rowdata->cells, 0);
2539 /* Add enough cells to the end of the line to fill out the
2541 vte_g_array_fill(rowdata->cells,
2542 &screen->fill_defaults,
2543 terminal->column_count);
2544 /* Repaint this row. */
2545 vte_invalidate_cells(terminal,
2546 0, terminal->column_count,
2547 screen->cursor_current.row, 1);
2550 /* We've modified the display. Make a note of it. */
2551 terminal->pvt->text_deleted_count++;
2555 /* Carriage return. */
2557 vte_sequence_handler_cr(VteTerminal *terminal,
2560 GValueArray *params)
2562 terminal->pvt->screen->cursor_current.col = 0;
2566 /* Restrict scrolling and updates to a subset of the visible lines. */
2568 vte_sequence_handler_cs(VteTerminal *terminal,
2571 GValueArray *params)
2573 long start, end, rows;
2577 /* We require two parameters. Anything less is a reset. */
2578 screen = terminal->pvt->screen;
2579 if ((params == NULL) || (params->n_values < 2)) {
2580 screen->scrolling_restricted = FALSE;
2583 /* Extract the two values. */
2584 value = g_value_array_get_nth(params, 0);
2585 start = g_value_get_long(value);
2586 value = g_value_array_get_nth(params, 1);
2587 end = g_value_get_long(value);
2588 /* Catch garbage. */
2589 rows = terminal->row_count;
2590 if ((start <= 0) || (start >= rows)) {
2593 if ((end <= 0) || (end >= rows)) {
2596 /* Set the right values. */
2597 screen->scrolling_region.start = start;
2598 screen->scrolling_region.end = end;
2599 screen->scrolling_restricted = TRUE;
2600 /* Special case -- run wild, run free. */
2601 if ((screen->scrolling_region.start == 0) &&
2602 (screen->scrolling_region.end == rows - 1)) {
2603 screen->scrolling_restricted = FALSE;
2605 /* Clamp the cursor to the scrolling region. */
2606 screen->cursor_current.row = CLAMP(screen->cursor_current.row,
2607 screen->insert_delta + start,
2608 screen->insert_delta + end);
2609 vte_terminal_ensure_cursor(terminal, TRUE);
2613 /* Restrict scrolling and updates to a subset of the visible lines, because
2614 * GNU Emacs is special. */
2616 vte_sequence_handler_cS(VteTerminal *terminal,
2619 GValueArray *params)
2621 long start, end, rows;
2625 /* We require four parameters. */
2626 screen = terminal->pvt->screen;
2627 if ((params == NULL) || (params->n_values < 2)) {
2628 screen->scrolling_restricted = FALSE;
2631 /* Extract the two parameters we care about, encoded as the number
2632 * of lines above and below the scrolling region, respectively. */
2633 value = g_value_array_get_nth(params, 1);
2634 start = g_value_get_long(value);
2635 value = g_value_array_get_nth(params, 2);
2636 end = (terminal->row_count - 1) - g_value_get_long(value);
2637 /* Set the right values. */
2638 screen->scrolling_region.start = start;
2639 screen->scrolling_region.end = end;
2640 screen->scrolling_restricted = TRUE;
2641 /* Special case -- run wild, run free. */
2642 rows = terminal->row_count;
2643 if ((screen->scrolling_region.start == 0) &&
2644 (screen->scrolling_region.end == rows - 1)) {
2645 screen->scrolling_restricted = FALSE;
2647 /* Clamp the cursor to the scrolling region. */
2648 screen->cursor_current.row = CLAMP(screen->cursor_current.row,
2649 screen->insert_delta + start,
2650 screen->insert_delta + end);
2651 vte_terminal_ensure_cursor(terminal, TRUE);
2655 /* Clear all tab stops. */
2657 vte_sequence_handler_ct(VteTerminal *terminal,
2660 GValueArray *params)
2662 if (terminal->pvt->tabstops != NULL) {
2663 g_hash_table_destroy(terminal->pvt->tabstops);
2664 terminal->pvt->tabstops = NULL;
2669 /* Move the cursor to the lower left-hand corner. */
2671 vte_sequence_handler_cursor_lower_left(VteTerminal *terminal,
2674 GValueArray *params)
2678 screen = terminal->pvt->screen;
2679 row = MAX(0, terminal->row_count - 1);
2680 screen->cursor_current.row = screen->insert_delta + row;
2681 screen->cursor_current.col = 0;
2682 vte_terminal_ensure_cursor(terminal, TRUE);
2686 /* Move the cursor to the beginning of the next line, scrolling if necessary. */
2688 vte_sequence_handler_cursor_next_line(VteTerminal *terminal,
2691 GValueArray *params)
2693 terminal->pvt->screen->cursor_current.col = 0;
2694 return vte_sequence_handler_DO(terminal, match, match_quark, params);
2697 /* Move the cursor to the beginning of the next line, scrolling if necessary. */
2699 vte_sequence_handler_cursor_preceding_line(VteTerminal *terminal,
2702 GValueArray *params)
2704 terminal->pvt->screen->cursor_current.col = 0;
2705 return vte_sequence_handler_UP(terminal, match, match_quark, params);
2708 /* Move the cursor to the given row (vertical position). */
2710 vte_sequence_handler_cv(VteTerminal *terminal,
2713 GValueArray *params)
2718 screen = terminal->pvt->screen;
2719 /* We only care if there's a parameter in there. */
2720 if ((params != NULL) && (params->n_values > 0)) {
2721 value = g_value_array_get_nth(params, 0);
2722 if (G_VALUE_HOLDS_LONG(value)) {
2723 /* Move the cursor. */
2724 if (screen->origin_mode &&
2725 screen->scrolling_restricted) {
2726 origin = screen->scrolling_region.start;
2730 val = g_value_get_long(value) + origin;
2731 val = CLAMP(val, 0, terminal->row_count - 1);
2732 screen->cursor_current.row = screen->insert_delta + val;
2738 /* Delete a character at the current cursor position. */
2740 vte_sequence_handler_dc(VteTerminal *terminal,
2743 GValueArray *params)
2746 VteRowData *rowdata;
2749 screen = terminal->pvt->screen;
2751 if (_vte_ring_next(screen->row_data) > screen->cursor_current.row) {
2752 /* Get the data for the row which the cursor points to. */
2753 rowdata = _vte_ring_index(screen->row_data,
2755 screen->cursor_current.row);
2756 col = screen->cursor_current.col;
2757 /* Remove the column. */
2758 if (col < rowdata->cells->len) {
2759 g_array_remove_index(rowdata->cells, col);
2761 /* Add new cells until we have enough to fill the row. */
2762 vte_g_array_fill(rowdata->cells,
2763 &screen->color_defaults,
2764 terminal->column_count);
2765 /* Repaint this row. */
2766 vte_invalidate_cells(terminal,
2767 0, terminal->column_count,
2768 screen->cursor_current.row, 1);
2771 /* We've modified the display. Make a note of it. */
2772 terminal->pvt->text_deleted_count++;
2776 /* Delete N characters at the current cursor position. */
2778 vte_sequence_handler_DC(VteTerminal *terminal,
2781 GValueArray *params)
2783 return vte_sequence_handler_multiple(terminal, match, match_quark,
2784 params, vte_sequence_handler_dc);
2787 /* Delete a line at the current cursor position. */
2789 vte_sequence_handler_dl(VteTerminal *terminal,
2792 GValueArray *params)
2795 long start, end, param, i;
2798 /* Find out which part of the screen we're messing with. */
2799 screen = terminal->pvt->screen;
2800 start = screen->cursor_current.row;
2801 if (screen->scrolling_restricted) {
2802 end = screen->insert_delta + screen->scrolling_region.end;
2804 end = screen->insert_delta + terminal->row_count - 1;
2807 /* Extract any parameters. */
2809 if ((params != NULL) && (params->n_values > 0)) {
2810 value = g_value_array_get_nth(params, 0);
2811 param = g_value_get_long(value);
2814 /* Delete the right number of lines. */
2815 for (i = 0; i < param; i++) {
2816 /* Clear a line off the end of the region and add one to the
2817 * top of the region. */
2818 vte_remove_line_internal(terminal, start);
2819 vte_insert_line_internal(terminal, end);
2820 /* Adjust the scrollbars if necessary. */
2821 vte_terminal_adjust_adjustments(terminal, FALSE);
2824 /* Update the display. */
2825 vte_terminal_scroll_region(terminal, start, end - start + 1, -param);
2827 /* We've modified the display. Make a note of it. */
2828 terminal->pvt->text_deleted_count++;
2832 /* Delete N lines at the current cursor position. */
2834 vte_sequence_handler_DL(VteTerminal *terminal,
2837 GValueArray *params)
2839 return vte_sequence_handler_dl(terminal, match, match_quark, params);
2842 /* Make sure we have enough rows and columns to hold data at the current
2843 * cursor position. */
2845 vte_terminal_ensure_cursor(VteTerminal *terminal, gboolean current)
2849 gboolean readjust = FALSE, fill = FALSE;
2851 /* Must make sure we're in a sane area. */
2852 screen = terminal->pvt->screen;
2854 /* Figure out how many rows we need to add. */
2855 fill = (terminal->pvt->screen->defaults.back != VTE_DEF_BG);
2856 while (screen->cursor_current.row >= _vte_ring_next(screen->row_data)) {
2857 /* Create a new row. */
2859 row = vte_new_row_data_sized(terminal, TRUE);
2861 row = vte_new_row_data(terminal);
2863 _vte_ring_append(screen->row_data, row);
2867 vte_terminal_adjust_adjustments(terminal, FALSE);
2870 /* Find the row the cursor is in. */
2871 row = _vte_ring_index(screen->row_data,
2873 screen->cursor_current.row);
2874 if ((row->cells->len <= screen->cursor_current.col) &&
2875 (row->cells->len < terminal->column_count)) {
2876 /* Set up defaults we'll use when adding new cells. */
2878 /* Add new cells until we have one here. */
2879 vte_g_array_fill(row->cells,
2880 &screen->color_defaults,
2881 screen->cursor_current.col + 1);
2883 /* Add enough cells at the end to make sure we have
2884 * enough for all visible columns. */
2885 vte_g_array_fill(row->cells,
2886 &screen->basic_defaults,
2887 screen->cursor_current.col + 1);
2892 /* Update the insert delta so that the screen which includes it also
2893 * includes the end of the buffer. */
2895 vte_terminal_update_insert_delta(VteTerminal *terminal)
2900 screen = terminal->pvt->screen;
2902 /* Make sure that the bottom row is visible, and that it's in
2903 * the buffer (even if it's empty). This usually causes the
2904 * top row to become a history-only row. */
2905 delta = MAX(screen->insert_delta,
2906 screen->cursor_current.row - (terminal->row_count - 1));
2907 delta = MAX(delta, _vte_ring_delta(screen->row_data));
2909 /* Adjust the insert delta and scroll if needed. */
2910 if (delta != screen->insert_delta) {
2911 vte_terminal_ensure_cursor(terminal, FALSE);
2912 vte_terminal_adjust_adjustments(terminal, TRUE);
2913 screen->insert_delta = delta;
2917 /* Cursor down, no scrolling. */
2919 vte_sequence_handler_do(VteTerminal *terminal,
2922 GValueArray *params)
2928 widget = GTK_WIDGET(terminal);
2929 screen = terminal->pvt->screen;
2931 if (screen->scrolling_restricted) {
2932 start = screen->insert_delta + screen->scrolling_region.start;
2933 end = screen->insert_delta + screen->scrolling_region.end;
2935 start = screen->insert_delta;
2936 end = start + terminal->row_count - 1;
2939 /* Move the cursor down. */
2940 screen->cursor_current.row = MIN(screen->cursor_current.row + 1, end);
2944 /* Cursor down, no scrolling. */
2946 vte_sequence_handler_DO(VteTerminal *terminal,
2949 GValueArray *params)
2951 return vte_sequence_handler_multiple(terminal, match, match_quark,
2952 params, vte_sequence_handler_do);
2955 /* Start using alternate character set. */
2957 vte_sequence_handler_eA(VteTerminal *terminal,
2960 GValueArray *params)
2962 return vte_sequence_handler_ae(terminal, match, match_quark, params);
2965 /* Erase characters starting at the cursor position (overwriting N with
2966 * spaces, but not moving the cursor). */
2968 vte_sequence_handler_ec(VteTerminal *terminal,
2971 GValueArray *params)
2974 VteRowData *rowdata;
2976 struct vte_charcell *cell;
2979 screen = terminal->pvt->screen;
2981 /* If we got a parameter, use it. */
2983 if ((params != NULL) && (params->n_values > 0)) {
2984 value = g_value_array_get_nth(params, 0);
2985 if (G_VALUE_HOLDS_LONG(value)) {
2986 count = g_value_get_long(value);
2990 /* Clear out the given number of characters. */
2991 vte_terminal_ensure_cursor(terminal, TRUE);
2992 if (_vte_ring_next(screen->row_data) > screen->cursor_current.row) {
2993 /* Get the data for the row which the cursor points to. */
2994 rowdata = _vte_ring_index(screen->row_data,
2996 screen->cursor_current.row);
2997 /* Write over the characters. (If there aren't enough, we'll
2998 * need to create them.) */
2999 for (i = 0; i < count; i++) {
3000 col = screen->cursor_current.col + i;
3002 if (col < rowdata->cells->len) {
3003 /* Replace this cell with the current
3005 cell = &g_array_index(rowdata->cells,
3006 struct vte_charcell,
3008 *cell = screen->color_defaults;
3010 /* Add new cells until we have one here. */
3011 vte_g_array_fill(rowdata->cells,
3012 &screen->color_defaults,
3017 /* Repaint this row. */
3018 vte_invalidate_cells(terminal,
3019 0, terminal->column_count,
3020 screen->cursor_current.row, 1);
3023 /* We've modified the display. Make a note of it. */
3024 terminal->pvt->text_deleted_count++;
3028 /* End insert mode. */
3030 vte_sequence_handler_ei(VteTerminal *terminal,
3033 GValueArray *params)
3035 terminal->pvt->screen->insert_mode = FALSE;
3039 /* Form-feed / next-page. */
3041 vte_sequence_handler_form_feed(VteTerminal *terminal,
3044 GValueArray *params)
3046 return vte_sequence_handler_index(terminal, match, match_quark, params);
3049 /* Move from status line. */
3051 vte_sequence_handler_fs(VteTerminal *terminal,
3054 GValueArray *params)
3056 terminal->pvt->screen->status_line = FALSE;
3060 /* Move the cursor to the home position. */
3062 vte_sequence_handler_ho(VteTerminal *terminal,
3065 GValueArray *params)
3068 screen = terminal->pvt->screen;
3069 screen->cursor_current.row = screen->insert_delta;
3070 screen->cursor_current.col = 0;
3074 /* Move the cursor to a specified position. */
3076 vte_sequence_handler_horizontal_and_vertical_position(VteTerminal *terminal,
3079 GValueArray *params)
3081 return vte_sequence_handler_offset(terminal, match, match_quark, params,
3082 -1, vte_sequence_handler_cm);
3085 /* Insert a character. */
3087 vte_sequence_handler_ic(VteTerminal *terminal,
3090 GValueArray *params)
3092 struct vte_cursor_position save;
3095 screen = terminal->pvt->screen;
3097 save = screen->cursor_current;
3099 vte_terminal_insert_char(terminal, ' ', TRUE, TRUE, TRUE, TRUE, 0);
3101 screen->cursor_current = save;
3106 /* Insert N characters. */
3108 vte_sequence_handler_IC(VteTerminal *terminal,
3111 GValueArray *params)
3113 return vte_sequence_handler_multiple(terminal, match, match_quark,
3114 params, vte_sequence_handler_ic);
3117 /* Begin insert mode. */
3119 vte_sequence_handler_im(VteTerminal *terminal,
3122 GValueArray *params)
3124 terminal->pvt->screen->insert_mode = TRUE;
3128 /* Cursor down, with scrolling. */
3130 vte_sequence_handler_index(VteTerminal *terminal,
3133 GValueArray *params)
3135 return vte_sequence_handler_sf(terminal, match, match_quark, params);
3138 /* Send me a backspace key sym, will you? Guess that the application meant
3139 * to send the cursor back one position. */
3141 vte_sequence_handler_kb(VteTerminal *terminal,
3144 GValueArray *params)
3146 /* Move the cursor left. */
3147 return vte_sequence_handler_le(terminal, match, match_quark, params);
3150 /* Keypad mode end. */
3152 vte_sequence_handler_ke(VteTerminal *terminal,
3155 GValueArray *params)
3157 terminal->pvt->keypad_mode = VTE_KEYMODE_NORMAL;
3161 /* Keypad mode start. */
3163 vte_sequence_handler_ks(VteTerminal *terminal,
3166 GValueArray *params)
3168 terminal->pvt->keypad_mode = VTE_KEYMODE_APPLICATION;
3174 vte_sequence_handler_le(VteTerminal *terminal,
3177 GValueArray *params)
3181 screen = terminal->pvt->screen;
3182 if (screen->cursor_current.col > 0) {
3183 /* There's room to move left, so do so. */
3184 screen->cursor_current.col--;
3186 if (terminal->pvt->flags.bw) {
3187 /* Wrap to the previous line. */
3188 screen->cursor_current.col = terminal->column_count - 1;
3189 screen->cursor_current.row = MAX(screen->cursor_current.row - 1,
3190 screen->insert_delta);
3192 /* Stick to the first column. */
3193 screen->cursor_current.col = 0;
3199 /* Move the cursor left N columns. */
3201 vte_sequence_handler_LE(VteTerminal *terminal,
3204 GValueArray *params)
3206 return vte_sequence_handler_multiple(terminal, match, match_quark,
3207 params, vte_sequence_handler_le);
3210 /* Move the cursor to the lower left corner of the display. */
3212 vte_sequence_handler_ll(VteTerminal *terminal,
3215 GValueArray *params)
3218 screen = terminal->pvt->screen;
3219 screen->cursor_current.row = MAX(screen->insert_delta,
3220 screen->insert_delta +
3221 terminal->row_count - 1);
3222 screen->cursor_current.col = 0;
3228 vte_sequence_handler_mb(VteTerminal *terminal,
3231 GValueArray *params)
3233 terminal->pvt->screen->defaults.blink = 1;
3239 vte_sequence_handler_md(VteTerminal *terminal,
3242 GValueArray *params)
3244 terminal->pvt->screen->defaults.bold = 1;
3245 terminal->pvt->screen->defaults.half = 0;
3251 vte_sequence_handler_me(VteTerminal *terminal,
3254 GValueArray *params)
3256 vte_terminal_set_default_attributes(terminal);
3260 /* Half-bright on. */
3262 vte_sequence_handler_mh(VteTerminal *terminal,
3265 GValueArray *params)
3267 terminal->pvt->screen->defaults.half = 1;
3268 terminal->pvt->screen->defaults.bold = 0;
3274 vte_sequence_handler_mk(VteTerminal *terminal,
3277 GValueArray *params)
3279 terminal->pvt->screen->defaults.invisible = 1;
3285 vte_sequence_handler_mp(VteTerminal *terminal,
3288 GValueArray *params)
3290 terminal->pvt->screen->defaults.protect = 1;
3296 vte_sequence_handler_mr(VteTerminal *terminal,
3299 GValueArray *params)
3301 terminal->pvt->screen->defaults.reverse = 1;
3307 vte_sequence_handler_nd(VteTerminal *terminal,
3310 GValueArray *params)
3313 screen = terminal->pvt->screen;
3314 if ((screen->cursor_current.col + 1) < terminal->column_count) {
3315 /* There's room to move right. */
3316 screen->cursor_current.col++;
3321 /* Move the cursor to the beginning of the next line, scrolling if necessary. */
3323 vte_sequence_handler_next_line(VteTerminal *terminal,
3326 GValueArray *params)
3328 terminal->pvt->screen->cursor_current.col = 0;
3329 return vte_sequence_handler_DO(terminal, match, match_quark, params);
3334 vte_sequence_handler_noop(VteTerminal *terminal,
3337 GValueArray *params)
3342 /* Carriage return command(?). */
3344 vte_sequence_handler_nw(VteTerminal *terminal,
3347 GValueArray *params)
3349 return vte_sequence_handler_cr(terminal, match, match_quark, params);
3352 /* Restore cursor (position). */
3354 vte_sequence_handler_rc(VteTerminal *terminal,
3357 GValueArray *params)
3360 screen = terminal->pvt->screen;
3361 screen->cursor_current.col = screen->cursor_saved.col;
3362 screen->cursor_current.row = CLAMP(screen->cursor_saved.row +
3363 screen->insert_delta,
3364 screen->insert_delta,
3365 screen->insert_delta +
3366 terminal->row_count - 1);
3370 /* Cursor down, with scrolling. */
3372 vte_sequence_handler_reverse_index(VteTerminal *terminal,
3375 GValueArray *params)
3377 return vte_sequence_handler_sr(terminal, match, match_quark, params);
3380 /* Cursor right N characters. */
3382 vte_sequence_handler_RI(VteTerminal *terminal,
3385 GValueArray *params)
3387 return vte_sequence_handler_multiple(terminal, match, match_quark,
3388 params, vte_sequence_handler_nd);
3391 /* Save cursor (position). */
3393 vte_sequence_handler_sc(VteTerminal *terminal,
3396 GValueArray *params)
3399 screen = terminal->pvt->screen;
3400 screen->cursor_saved.col = screen->cursor_current.col;
3401 screen->cursor_saved.row = CLAMP(screen->cursor_current.row -
3402 screen->insert_delta,
3403 0, terminal->row_count - 1);
3409 vte_sequence_handler_se(VteTerminal *terminal,
3412 GValueArray *params)
3414 char *bold, *underline, *standout, *reverse, *half, *blink;
3416 /* Standout may be mapped to another attribute, so attempt to do
3417 * the Right Thing here. */
3418 standout = _vte_termcap_find_string(terminal->pvt->termcap,
3419 terminal->pvt->emulation,
3421 g_assert(standout != NULL);
3422 blink = _vte_termcap_find_string(terminal->pvt->termcap,
3423 terminal->pvt->emulation,
3425 bold = _vte_termcap_find_string(terminal->pvt->termcap,
3426 terminal->pvt->emulation,
3428 half = _vte_termcap_find_string(terminal->pvt->termcap,
3429 terminal->pvt->emulation,
3431 reverse = _vte_termcap_find_string(terminal->pvt->termcap,
3432 terminal->pvt->emulation,
3434 underline = _vte_termcap_find_string(terminal->pvt->termcap,
3435 terminal->pvt->emulation,
3438 /* If the standout sequence is the same as another sequence, do what
3439 * we'd do for that other sequence instead. */
3440 if (blink && (g_ascii_strcasecmp(standout, blink) == 0)) {
3441 vte_sequence_handler_me(terminal, match, match_quark, params);
3443 if (bold && (g_ascii_strcasecmp(standout, bold) == 0)) {
3444 vte_sequence_handler_me(terminal, match, match_quark, params);
3446 if (half && (g_ascii_strcasecmp(standout, half) == 0)) {
3447 vte_sequence_handler_me(terminal, match, match_quark, params);
3449 if (reverse && (g_ascii_strcasecmp(standout, reverse) == 0)) {
3450 vte_sequence_handler_me(terminal, match, match_quark, params);
3452 if (underline && (g_ascii_strcasecmp(standout, underline) == 0)) {
3453 vte_sequence_handler_ue(terminal, match, match_quark, params);
3455 /* Otherwise just set standout mode. */
3456 terminal->pvt->screen->defaults.standout = 0;
3478 /* Cursor down, with scrolling. */
3480 vte_sequence_handler_sf(VteTerminal *terminal,
3483 GValueArray *params)
3487 long start, end, top, bottom;
3490 widget = GTK_WIDGET(terminal);
3491 screen = terminal->pvt->screen;
3493 if (screen->scrolling_restricted) {
3494 start = screen->insert_delta + screen->scrolling_region.start;
3495 end = screen->insert_delta + screen->scrolling_region.end;
3497 start = screen->insert_delta;
3498 end = start + terminal->row_count - 1;
3501 if (screen->cursor_current.row == end) {
3502 if (screen->scrolling_restricted) {
3503 if (start == screen->insert_delta) {
3504 /* Scroll this line into the scrollback
3505 * buffer by inserting a line at the next
3506 * line and scrolling the area up. */
3507 row = vte_new_row_data_sized(terminal, TRUE);
3508 screen->insert_delta++;
3509 screen->scroll_delta++;
3510 screen->cursor_current.row++;
3511 _vte_ring_insert_preserve(terminal->pvt->screen->row_data,
3512 screen->cursor_current.row,
3514 /* This may generate multiple redraws, so
3515 * disable fast scrolling for now. */
3516 terminal->pvt->scroll_lock_count++;
3517 gdk_window_freeze_updates(widget->window);
3518 /* Force the areas below the region to be
3519 * redrawn -- they've moved. */
3520 top = screen->cursor_current.row;
3521 bottom = screen->insert_delta +
3522 terminal->row_count - 1;
3523 vte_terminal_scroll_region(terminal, start,
3524 end - start + 1, 1);
3526 vte_terminal_ensure_cursor(terminal, FALSE);
3527 vte_terminal_adjust_adjustments(terminal, TRUE);
3528 /* Allow updates again. */
3529 gdk_window_thaw_updates(widget->window);
3530 terminal->pvt->scroll_lock_count--;
3532 /* If we're at the bottom of the scrolling
3533 * region, add a line at the top to scroll the
3535 vte_remove_line_internal(terminal, start);
3536 vte_insert_line_internal(terminal, end);
3537 /* This may generate multiple redraws, so
3538 * disable fast scrolling for now. */
3539 terminal->pvt->scroll_lock_count++;
3540 gdk_window_freeze_updates(widget->window);
3541 /* Update the display. */
3542 vte_terminal_scroll_region(terminal, start,
3543 end - start + 1, -1);
3544 vte_invalidate_cells(terminal,
3545 0, terminal->column_count,
3547 /* Allow updates again. */
3548 gdk_window_thaw_updates(widget->window);
3549 terminal->pvt->scroll_lock_count--;
3552 /* Scroll up with history. */
3553 screen->cursor_current.row++;
3554 vte_terminal_update_insert_delta(terminal);
3557 /* Otherwise, just move the cursor down. */
3558 screen->cursor_current.row++;
3559 vte_terminal_ensure_cursor(terminal, TRUE);
3561 /* Adjust the scrollbars if necessary. */
3562 vte_terminal_adjust_adjustments(terminal, FALSE);
3566 /* Cursor down, with scrolling. */
3568 vte_sequence_handler_SF(VteTerminal *terminal,
3571 GValueArray *params)
3573 return vte_sequence_handler_multiple(terminal, match, match_quark,
3574 params, vte_sequence_handler_sf);
3577 /* Standout start. */
3579 vte_sequence_handler_so(VteTerminal *terminal,
3582 GValueArray *params)
3584 char *bold, *underline, *standout, *reverse, *half, *blink;
3586 /* Standout may be mapped to another attribute, so attempt to do
3587 * the Right Thing here. */
3588 standout = _vte_termcap_find_string(terminal->pvt->termcap,
3589 terminal->pvt->emulation,
3591 g_assert(standout != NULL);
3592 blink = _vte_termcap_find_string(terminal->pvt->termcap,
3593 terminal->pvt->emulation,
3595 bold = _vte_termcap_find_string(terminal->pvt->termcap,
3596 terminal->pvt->emulation,
3598 half = _vte_termcap_find_string(terminal->pvt->termcap,
3599 terminal->pvt->emulation,
3601 reverse = _vte_termcap_find_string(terminal->pvt->termcap,
3602 terminal->pvt->emulation,
3604 underline = _vte_termcap_find_string(terminal->pvt->termcap,
3605 terminal->pvt->emulation,
3608 /* If the standout sequence is the same as another sequence, do what
3609 * we'd do for that other sequence instead. */
3610 if (blink && (g_ascii_strcasecmp(standout, blink) == 0)) {
3611 vte_sequence_handler_mb(terminal, match, match_quark, params);
3613 if (bold && (g_ascii_strcasecmp(standout, bold) == 0)) {
3614 vte_sequence_handler_md(terminal, match, match_quark, params);
3616 if (half && (g_ascii_strcasecmp(standout, half) == 0)) {
3617 vte_sequence_handler_mh(terminal, match, match_quark, params);
3619 if (reverse && (g_ascii_strcasecmp(standout, reverse) == 0)) {
3620 vte_sequence_handler_mr(terminal, match, match_quark, params);
3622 if (underline && (g_ascii_strcasecmp(standout, underline) == 0)) {
3623 vte_sequence_handler_us(terminal, match, match_quark, params);
3625 /* Otherwise just set standout mode. */
3626 terminal->pvt->screen->defaults.standout = 1;
3648 /* Cursor up, scrolling if need be. */
3650 vte_sequence_handler_sr(VteTerminal *terminal,
3653 GValueArray *params)
3659 widget = GTK_WIDGET(terminal);
3660 screen = terminal->pvt->screen;
3662 if (screen->scrolling_restricted) {
3663 start = screen->scrolling_region.start + screen->insert_delta;
3664 end = screen->scrolling_region.end + screen->insert_delta;
3666 start = terminal->pvt->screen->insert_delta;
3667 end = start + terminal->row_count - 1;
3670 if (screen->cursor_current.row == start) {
3671 /* If we're at the top of the scrolling region, add a
3672 * line at the top to scroll the bottom off. */
3673 vte_remove_line_internal(terminal, end);
3674 vte_insert_line_internal(terminal, start);
3675 /* Update the display. */
3676 vte_terminal_scroll_region(terminal, start, end - start + 1, 1);
3677 vte_invalidate_cells(terminal,
3678 0, terminal->column_count,
3681 /* Otherwise, just move the cursor up. */
3682 screen->cursor_current.row--;
3684 /* Adjust the scrollbars if necessary. */
3685 vte_terminal_adjust_adjustments(terminal, FALSE);
3686 /* We modified the display, so make a note of it. */
3687 terminal->pvt->text_modified_flag = TRUE;
3691 /* Cursor up, with scrolling. */
3693 vte_sequence_handler_SR(VteTerminal *terminal,
3696 GValueArray *params)
3698 return vte_sequence_handler_multiple(terminal, match, match_quark,
3699 params, vte_sequence_handler_sr);
3702 /* Set tab stop in the current column. */
3704 vte_sequence_handler_st(VteTerminal *terminal,
3707 GValueArray *params)
3709 if (terminal->pvt->tabstops == NULL) {
3710 terminal->pvt->tabstops = g_hash_table_new(g_direct_hash,
3713 vte_terminal_set_tabstop(terminal,
3714 terminal->pvt->screen->cursor_current.col);
3720 vte_sequence_handler_ta(VteTerminal *terminal,
3723 GValueArray *params)
3727 /* Calculate which column is the next tab stop. */
3728 newcol = terminal->pvt->screen->cursor_current.col;
3730 if (terminal->pvt->tabstops != NULL) {
3731 /* Find the next tabstop. */
3732 for (newcol++; newcol < VTE_TAB_MAX; newcol++) {
3733 if (vte_terminal_get_tabstop(terminal, newcol)) {
3739 /* If we have no tab stops or went past the end of the line, stop
3740 * at the right-most column. */
3741 if (newcol >= terminal->column_count) {
3742 newcol = terminal->column_count - 1;
3745 terminal->pvt->screen->cursor_current.col = newcol;
3749 /* Clear tabs selectively. */
3751 vte_sequence_handler_tab_clear(VteTerminal *terminal,
3754 GValueArray *params)
3759 if ((params != NULL) && (params->n_values > 0)) {
3760 value = g_value_array_get_nth(params, 0);
3761 if (G_VALUE_HOLDS_LONG(value)) {
3762 param = g_value_get_long(value);
3766 vte_terminal_clear_tabstop(terminal,
3767 terminal->pvt->screen->cursor_current.col);
3770 if (terminal->pvt->tabstops != NULL) {
3771 g_hash_table_destroy(terminal->pvt->tabstops);
3772 terminal->pvt->tabstops = NULL;
3778 /* Move to status line. */
3780 vte_sequence_handler_ts(VteTerminal *terminal,
3783 GValueArray *params)
3785 terminal->pvt->screen->status_line = TRUE;
3786 g_string_truncate(terminal->pvt->screen->status_line_contents, 0);
3787 vte_terminal_emit_status_line_changed(terminal);
3791 /* Underline this character and move right. */
3793 vte_sequence_handler_uc(VteTerminal *terminal,
3796 GValueArray *params)
3798 struct vte_charcell *cell;
3802 screen = terminal->pvt->screen;
3803 column = screen->cursor_current.col;
3804 cell = vte_terminal_find_charcell(terminal,
3806 screen->cursor_current.row);
3807 while ((cell != NULL) && (cell->fragment) && (column > 0)) {
3809 cell = vte_terminal_find_charcell(terminal,
3811 screen->cursor_current.row);
3814 /* Set this character to be underlined. */
3815 cell->underline = 1;
3816 /* Cause the character to be repainted. */
3817 vte_invalidate_cells(terminal,
3818 column, cell->columns,
3819 screen->cursor_current.row, 1);
3820 /* Move the cursor right. */
3821 vte_sequence_handler_nd(terminal, match, match_quark, params);
3824 /* We've modified the display without changing the text. Make a note
3826 terminal->pvt->text_modified_flag = TRUE;
3830 /* Underline end. */
3832 vte_sequence_handler_ue(VteTerminal *terminal,
3835 GValueArray *params)
3837 terminal->pvt->screen->defaults.underline = 0;
3841 /* Cursor up, no scrolling. */
3843 vte_sequence_handler_up(VteTerminal *terminal,
3846 GValueArray *params)
3851 screen = terminal->pvt->screen;
3853 if (screen->scrolling_restricted) {
3854 start = screen->insert_delta + screen->scrolling_region.start;
3855 end = screen->insert_delta + screen->scrolling_region.end;
3857 start = screen->insert_delta;
3858 end = start + terminal->row_count - 1;
3861 screen->cursor_current.row = MAX(screen->cursor_current.row - 1, start);
3865 /* Cursor up N lines, no scrolling. */
3867 vte_sequence_handler_UP(VteTerminal *terminal,
3870 GValueArray *params)
3872 return vte_sequence_handler_multiple(terminal, match, match_quark,
3873 params, vte_sequence_handler_up);
3876 /* Underline start. */
3878 vte_sequence_handler_us(VteTerminal *terminal,
3881 GValueArray *params)
3883 terminal->pvt->screen->defaults.underline = 1;
3889 vte_sequence_handler_vb(VteTerminal *terminal,
3892 GValueArray *params)
3895 gint width, height, state;
3897 widget = GTK_WIDGET(terminal);
3898 if (GTK_WIDGET_REALIZED(widget)) {
3899 gdk_drawable_get_size(widget->window, &width, &height);
3900 state = GTK_WIDGET_STATE(widget);
3901 /* Fill the screen with the default foreground color, and then
3902 * repaint everything, to provide visual bell. */
3903 gdk_draw_rectangle(widget->window,
3904 widget->style->fg_gc[state],
3908 gdk_window_process_updates(widget->window, TRUE);
3909 /* Force the repaint. */
3910 vte_invalidate_all(terminal);
3911 gdk_window_process_updates(widget->window, TRUE);
3916 /* Cursor visible. */
3918 vte_sequence_handler_ve(VteTerminal *terminal,
3921 GValueArray *params)
3923 terminal->pvt->cursor_visible = TRUE;
3929 vte_sequence_handler_vertical_tab(VteTerminal *terminal,
3932 GValueArray *params)
3934 return vte_sequence_handler_index(terminal, match, match_quark, params);
3937 /* Cursor invisible. */
3939 vte_sequence_handler_vi(VteTerminal *terminal,
3942 GValueArray *params)
3944 terminal->pvt->cursor_visible = FALSE;
3948 /* Cursor standout. */
3950 vte_sequence_handler_vs(VteTerminal *terminal,
3953 GValueArray *params)
3955 terminal->pvt->cursor_visible = TRUE; /* FIXME: should be *more*
3960 /* Handle ANSI color setting and related stuffs (SGR). */
3962 vte_sequence_handler_character_attributes(VteTerminal *terminal,
3965 GValueArray *params)
3970 /* The default parameter is zero. */
3972 /* Step through each numeric parameter. */
3973 for (i = 0; (params != NULL) && (i < params->n_values); i++) {
3974 /* If this parameter isn't a number, skip it. */
3975 value = g_value_array_get_nth(params, i);
3976 if (!G_VALUE_HOLDS_LONG(value)) {
3979 param = g_value_get_long(value);
3982 vte_terminal_set_default_attributes(terminal);
3985 terminal->pvt->screen->defaults.bold = 1;
3986 terminal->pvt->screen->defaults.half = 0;
3989 terminal->pvt->screen->defaults.half = 1;
3990 terminal->pvt->screen->defaults.bold = 0;
3993 terminal->pvt->screen->defaults.underline = 1;
3996 terminal->pvt->screen->defaults.blink = 1;
3999 terminal->pvt->screen->defaults.reverse = 1;
4002 terminal->pvt->screen->defaults.invisible = 1;
4005 terminal->pvt->screen->defaults.strikethrough = 1;
4007 case 21: /* Error in old versions of linux console. */
4008 case 22: /* ECMA 48. */
4009 terminal->pvt->screen->defaults.bold = 0;
4010 terminal->pvt->screen->defaults.half = 0;
4013 terminal->pvt->screen->defaults.underline = 0;
4016 terminal->pvt->screen->defaults.blink = 0;
4019 terminal->pvt->screen->defaults.reverse = 0;
4022 terminal->pvt->screen->defaults.invisible = 0;
4025 terminal->pvt->screen->defaults.strikethrough = 0;
4035 terminal->pvt->screen->defaults.fore = param - 30;
4038 /* default foreground, underscore */
4039 terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
4040 terminal->pvt->screen->defaults.underline = 1;
4043 /* default foreground, no underscore */
4044 terminal->pvt->screen->defaults.fore = VTE_DEF_FG;
4045 /* By ECMA 48, this underline off has no business
4046 being here, but the Linux console specifies it. */
4047 terminal->pvt->screen->defaults.underline = 0;
4057 terminal->pvt->screen->defaults.back = param - 40;
4060 /* default background */
4061 terminal->pvt->screen->defaults.back = VTE_DEF_BG;
4071 terminal->pvt->screen->defaults.fore = param - 90 + VTE_COLOR_BRIGHT_OFFSET;
4081 terminal->pvt->screen->defaults.back = param - 100 + VTE_COLOR_BRIGHT_OFFSET;