--- vte.c.orig 2004-04-22 12:39:39.000000000 -0400 +++ vte.c 2004-04-22 12:39:46.000000000 -0400 @@ -16,7 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ident "$Id: vte.c,v 1.369 2003/06/16 21:15:09 nalin Exp $" +#ident "$Id: vte.c,v 1.393 2004/04/22 03:44:54 nalin Exp $" #include "../config.h" @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -62,6 +61,7 @@ #include "vteconv.h" #include "vtedraw.h" #include "vteint.h" +#include "vteregex.h" #include "vtetc.h" #include @@ -92,6 +92,8 @@ #define VTE_DEF_BG 25 #define VTE_BOLD_FG 26 #define VTE_DIM_FG 27 +#define VTE_DEF_HL 28 +#define VTE_CUR_BG 29 #define VTE_SATURATION_MAX 10000 #define VTE_SCROLLBACK_MIN 100 #define VTE_DEFAULT_EMULATION "xterm" @@ -136,7 +138,7 @@ /* A match regex, with a tag. */ struct vte_match_regex { - regex_t reg; + struct _vte_regex *reg; gint tag; GdkCursor *cursor; }; @@ -172,6 +174,7 @@ gboolean am; gboolean bw; gboolean ul; + gboolean xn; } flags; int keypad_mode, cursor_mode; /* these would be VteKeymodes, but we need to guarantee its type */ @@ -239,7 +242,7 @@ plus the current fore/back */ struct vte_charcell fill_defaults; /* original defaults - plust the current + plus the current fore/back with no character data */ struct vte_charcell basic_defaults; /* original defaults */ @@ -319,6 +322,7 @@ /* Data used when rendering the text which does not require server * resources and which can be kept after unrealizing. */ PangoFontDescription *fontdesc; + VteTerminalAntiAlias fontantialias; GtkSettings *connected_settings; /* Data used when rendering the text which reflects server resources @@ -327,9 +331,11 @@ struct _vte_draw *draw; gboolean palette_initialized; + gboolean highlight_color_set; + gboolean cursor_color_set; struct vte_palette_entry { guint16 red, green, blue; - } palette[VTE_DIM_FG + 1]; + } palette[VTE_CUR_BG + 1]; /* Mouse cursors. */ gboolean mouse_cursor_visible; @@ -341,6 +347,7 @@ GtkIMContext *im_context; gboolean im_preedit_active; char *im_preedit; + PangoAttrList *im_preedit_attrs; int im_preedit_cursor; /* Our accessible peer. */ @@ -366,11 +373,13 @@ GdkVisibilityState visibility_state; }; -/* A function which can handle a terminal control sequence. */ -typedef void (*VteTerminalSequenceHandler)(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); +/* A function which can handle a terminal control sequence. Returns TRUE only + * if something happened (usually a signal emission) to which the controlling + * application must have an immediate opportunity to respond. */ +typedef gboolean (*VteTerminalSequenceHandler)(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); static void vte_terminal_set_termcap(VteTerminal *terminal, const char *path, gboolean reset); static void vte_terminal_ensure_cursor(VteTerminal *terminal, gboolean current); @@ -381,62 +390,66 @@ gboolean paint_cells, gboolean ensure_after, gint forced_width); -static void vte_sequence_handler_clear_screen(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_do(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_DO(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_ho(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_le(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_LE(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_nd(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_sf(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_sr(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_ue(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_up(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_UP(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_us(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); -static void vte_sequence_handler_vb(VteTerminal *terminal, - const char *match, - GQuark match_quark, - GValueArray *params); +static gboolean vte_sequence_handler_clear_screen(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_do(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_DO(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_ho(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_index(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_le(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_LE(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_nd(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_sf(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_sr(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_ue(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_up(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_UP(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_us(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); +static gboolean vte_sequence_handler_vb(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params); static gboolean vte_terminal_io_read(GIOChannel *channel, GdkInputCondition condition, gpointer data); @@ -1378,8 +1391,8 @@ gdk_cursor_unref(regex->cursor); regex->cursor = NULL; } - regfree(®ex->reg); - memset(®ex->reg, 0, sizeof(regex->reg)); + _vte_regex_free(regex->reg); + regex->reg = NULL; regex->tag = -1; } } @@ -1416,8 +1429,8 @@ gdk_cursor_unref(regex->cursor); regex->cursor = NULL; } - regfree(®ex->reg); - memset(®ex->reg, 0, sizeof(regex->reg)); + _vte_regex_free(regex->reg); + regex->reg = NULL; regex->tag = -1; } vte_terminal_match_hilite_clear(terminal); @@ -1461,9 +1474,11 @@ struct vte_match_regex new_regex, *regex; int ret; g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); + g_return_val_if_fail(match != NULL, -1); + g_return_val_if_fail(strlen(match) > 0, -1); memset(&new_regex, 0, sizeof(new_regex)); - ret = regcomp(&new_regex.reg, match, VTE_REGCOMP_FLAGS); - if (ret != 0) { + new_regex.reg = _vte_regex_compile(match); + if (new_regex.reg == NULL) { g_warning(_("Error compiling regular expression \"%s\"."), match); return -1; @@ -1558,7 +1573,7 @@ struct vte_match_regex *regex = NULL; struct _VteCharAttributes *attr = NULL; gssize coffset; - regmatch_t matches[256]; + struct _vte_regex_match matches[256]; #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_EVENTS)) { fprintf(stderr, "Checking for match at (%ld,%ld).\n", @@ -1632,11 +1647,10 @@ * matches, so we'll have to skip each match until we * stop getting matches. */ coffset = 0; - ret = regexec(®ex->reg, - terminal->pvt->match_contents + coffset, - G_N_ELEMENTS(matches), - matches, - VTE_REGEXEC_FLAGS); + ret = _vte_regex_exec(regex->reg, + terminal->pvt->match_contents + coffset, + G_N_ELEMENTS(matches), + matches); while (ret == 0) { for (j = 0; (j < G_N_ELEMENTS(matches)) && @@ -1704,11 +1718,11 @@ /* Skip past the beginning of this match to * look for more. */ coffset += (matches[0].rm_so + 1); - ret = regexec(®ex->reg, - terminal->pvt->match_contents + coffset, - G_N_ELEMENTS(matches), - matches, - VTE_REGEXEC_FLAGS); + ret = _vte_regex_exec(regex->reg, + terminal->pvt->match_contents + + coffset, + G_N_ELEMENTS(matches), + matches); } } terminal->pvt->match_previous = -1; @@ -1944,7 +1958,7 @@ /* Call another function, offsetting any long arguments by the given * increment value. */ -static void +static gboolean vte_sequence_handler_offset(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -1964,11 +1978,11 @@ g_value_set_long(value, val); } } - handler(terminal, match, match_quark, params); + return handler(terminal, match, match_quark, params); } /* Call another function a given number of times, or once. */ -static void +static gboolean vte_sequence_handler_multiple(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -1976,8 +1990,9 @@ VteTerminalSequenceHandler handler) { long val = 1; - int i; + int i, again; GValue *value; + if ((params != NULL) && (params->n_values > 0)) { value = g_value_array_get_nth(params, 0); if (G_VALUE_HOLDS_LONG(value)) { @@ -1985,9 +2000,13 @@ val = MAX(val, 1); /* FIXME: vttest. */ } } + again = 0; for (i = 0; i < val; i++) { - handler(terminal, match, match_quark, NULL); + if (handler(terminal, match, match_quark, NULL)) { + again++; + } } + return (again > 0); } /* Insert a blank line at an arbitrary position. */ @@ -2064,6 +2083,8 @@ /* Set the terminal's encoding to the new value. */ encoding_quark = g_quark_from_string(codeset); terminal->pvt->encoding = g_quark_to_string(encoding_quark); + _vte_pty_set_utf8(terminal->pvt->pty_master, + (strcmp(codeset, "UTF-8") == 0)); /* Convert any buffered output bytes. */ if ((_vte_buffer_length(terminal->pvt->outgoing) > 0) && @@ -2125,17 +2146,18 @@ } /* End alternate character set. */ -static void +static gboolean vte_sequence_handler_ae(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.alternate = 0; + return FALSE; } /* Add a line at the current cursor position. */ -static void +static gboolean vte_sequence_handler_al(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2183,26 +2205,28 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Add N lines at the current cursor position. */ -static void +static gboolean vte_sequence_handler_AL(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_al(terminal, match, match_quark, params); + return vte_sequence_handler_al(terminal, match, match_quark, params); } /* Start using alternate character set. */ -static void +static gboolean vte_sequence_handler_as(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.alternate = 1; + return FALSE; } static void @@ -2220,7 +2244,7 @@ } /* Beep. */ -static void +static gboolean vte_sequence_handler_bl(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2234,10 +2258,11 @@ /* Visual bell. */ vte_sequence_handler_vb(terminal, match, match_quark, params); } + return FALSE; } /* Backtab. */ -static void +static gboolean vte_sequence_handler_bt(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2271,10 +2296,11 @@ } #endif terminal->pvt->screen->cursor_current.col = newcol; + return FALSE; } /* Clear from the cursor position to the beginning of the line. */ -static void +static gboolean vte_sequence_handler_cb(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2314,10 +2340,11 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Clear to the right of the cursor and below the current line. */ -static void +static gboolean vte_sequence_handler_cd(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2376,10 +2403,11 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Clear from the cursor position to the end of the line. */ -static void +static gboolean vte_sequence_handler_ce(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2409,10 +2437,11 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Move the cursor to the given column (horizontal position). */ -static void +static gboolean vte_sequence_handler_ch(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2434,10 +2463,11 @@ screen->cursor_current.col = val; } } + return FALSE; } /* Clear the screen and home the cursor. */ -static void +static gboolean vte_sequence_handler_cl(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2448,10 +2478,11 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Move the cursor to the given position. */ -static void +static gboolean vte_sequence_handler_cm(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2484,10 +2515,11 @@ screen->cursor_current.col = colval; } } + return FALSE; } /* Clear the current line. */ -static void +static gboolean vte_sequence_handler_clear_current_line(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2521,20 +2553,22 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Carriage return. */ -static void +static gboolean vte_sequence_handler_cr(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->cursor_current.col = 0; + return FALSE; } /* Restrict scrolling and updates to a subset of the visible lines. */ -static void +static gboolean vte_sequence_handler_cs(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2548,7 +2582,7 @@ screen = terminal->pvt->screen; if ((params == NULL) || (params->n_values < 2)) { screen->scrolling_restricted = FALSE; - return; + return FALSE; } /* Extract the two values. */ value = g_value_array_get_nth(params, 0); @@ -2577,11 +2611,12 @@ screen->insert_delta + start, screen->insert_delta + end); vte_terminal_ensure_cursor(terminal, TRUE); + return FALSE; } /* Restrict scrolling and updates to a subset of the visible lines, because * GNU Emacs is special. */ -static void +static gboolean vte_sequence_handler_cS(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2595,7 +2630,7 @@ screen = terminal->pvt->screen; if ((params == NULL) || (params->n_values < 2)) { screen->scrolling_restricted = FALSE; - return; + return FALSE; } /* Extract the two parameters we care about, encoded as the number * of lines above and below the scrolling region, respectively. */ @@ -2618,10 +2653,11 @@ screen->insert_delta + start, screen->insert_delta + end); vte_terminal_ensure_cursor(terminal, TRUE); + return FALSE; } /* Clear all tab stops. */ -static void +static gboolean vte_sequence_handler_ct(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2631,10 +2667,11 @@ g_hash_table_destroy(terminal->pvt->tabstops); terminal->pvt->tabstops = NULL; } + return FALSE; } /* Move the cursor to the lower left-hand corner. */ -static void +static gboolean vte_sequence_handler_cursor_lower_left(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2647,32 +2684,33 @@ screen->cursor_current.row = screen->insert_delta + row; screen->cursor_current.col = 0; vte_terminal_ensure_cursor(terminal, TRUE); + return FALSE; } /* Move the cursor to the beginning of the next line, scrolling if necessary. */ -static void +static gboolean vte_sequence_handler_cursor_next_line(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->cursor_current.col = 0; - vte_sequence_handler_DO(terminal, match, match_quark, params); + return vte_sequence_handler_DO(terminal, match, match_quark, params); } /* Move the cursor to the beginning of the next line, scrolling if necessary. */ -static void +static gboolean vte_sequence_handler_cursor_preceding_line(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->cursor_current.col = 0; - vte_sequence_handler_UP(terminal, match, match_quark, params); + return vte_sequence_handler_UP(terminal, match, match_quark, params); } /* Move the cursor to the given row (vertical position). */ -static void +static gboolean vte_sequence_handler_cv(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2698,10 +2736,11 @@ screen->cursor_current.row = screen->insert_delta + val; } } + return FALSE; } /* Delete a character at the current cursor position. */ -static void +static gboolean vte_sequence_handler_dc(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2735,21 +2774,22 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Delete N characters at the current cursor position. */ -static void +static gboolean vte_sequence_handler_DC(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_dc); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_dc); } /* Delete a line at the current cursor position. */ -static void +static gboolean vte_sequence_handler_dl(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2790,16 +2830,17 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Delete N lines at the current cursor position. */ -static void +static gboolean vte_sequence_handler_DL(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_dl(terminal, match, match_quark, params); + return vte_sequence_handler_dl(terminal, match, match_quark, params); } /* Make sure we have enough rows and columns to hold data at the current @@ -2878,7 +2919,7 @@ } /* Cursor down, no scrolling. */ -static void +static gboolean vte_sequence_handler_do(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2901,32 +2942,33 @@ /* Move the cursor down. */ screen->cursor_current.row = MIN(screen->cursor_current.row + 1, end); + return FALSE; } /* Cursor down, no scrolling. */ -static void +static gboolean vte_sequence_handler_DO(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_do); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_do); } /* Start using alternate character set. */ -static void +static gboolean vte_sequence_handler_eA(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_ae(terminal, match, match_quark, params); + return vte_sequence_handler_ae(terminal, match, match_quark, params); } /* Erase characters starting at the cursor position (overwriting N with * spaces, but not moving the cursor). */ -static void +static gboolean vte_sequence_handler_ec(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -2984,30 +3026,43 @@ /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* End insert mode. */ -static void +static gboolean vte_sequence_handler_ei(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->insert_mode = FALSE; + return FALSE; +} + +/* Form-feed / next-page. */ +static gboolean +vte_sequence_handler_form_feed(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params) +{ + return vte_sequence_handler_index(terminal, match, match_quark, params); } /* Move from status line. */ -static void +static gboolean vte_sequence_handler_fs(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->status_line = FALSE; + return FALSE; } /* Move the cursor to the home position. */ -static void +static gboolean vte_sequence_handler_ho(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3017,21 +3072,22 @@ screen = terminal->pvt->screen; screen->cursor_current.row = screen->insert_delta; screen->cursor_current.col = 0; + return FALSE; } /* Move the cursor to a specified position. */ -static void +static gboolean vte_sequence_handler_horizontal_and_vertical_position(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_offset(terminal, match, match_quark, params, - -1, vte_sequence_handler_cm); + return vte_sequence_handler_offset(terminal, match, match_quark, params, + -1, vte_sequence_handler_cm); } /* Insert a character. */ -static void +static gboolean vte_sequence_handler_ic(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3047,73 +3103,78 @@ vte_terminal_insert_char(terminal, ' ', TRUE, TRUE, TRUE, TRUE, 0); screen->cursor_current = save; + + return FALSE; } /* Insert N characters. */ -static void +static gboolean vte_sequence_handler_IC(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_ic); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_ic); } /* Begin insert mode. */ -static void +static gboolean vte_sequence_handler_im(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->insert_mode = TRUE; + return FALSE; } /* Cursor down, with scrolling. */ -static void +static gboolean vte_sequence_handler_index(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_sf(terminal, match, match_quark, params); + return vte_sequence_handler_sf(terminal, match, match_quark, params); } /* Send me a backspace key sym, will you? Guess that the application meant * to send the cursor back one position. */ -static void +static gboolean vte_sequence_handler_kb(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { /* Move the cursor left. */ - vte_sequence_handler_le(terminal, match, match_quark, params); + return vte_sequence_handler_le(terminal, match, match_quark, params); } /* Keypad mode end. */ -static void +static gboolean vte_sequence_handler_ke(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->keypad_mode = VTE_KEYMODE_NORMAL; + return FALSE; } /* Keypad mode start. */ -static void +static gboolean vte_sequence_handler_ks(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->keypad_mode = VTE_KEYMODE_APPLICATION; + return FALSE; } /* Cursor left. */ -static void +static gboolean vte_sequence_handler_le(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3136,21 +3197,22 @@ screen->cursor_current.col = 0; } } + return FALSE; } /* Move the cursor left N columns. */ -static void +static gboolean vte_sequence_handler_LE(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_le); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_le); } /* Move the cursor to the lower left corner of the display. */ -static void +static gboolean vte_sequence_handler_ll(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3162,20 +3224,22 @@ screen->insert_delta + terminal->row_count - 1); screen->cursor_current.col = 0; + return FALSE; } /* Blink on. */ -static void +static gboolean vte_sequence_handler_mb(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.blink = 1; + return FALSE; } /* Bold on. */ -static void +static gboolean vte_sequence_handler_md(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3183,20 +3247,22 @@ { terminal->pvt->screen->defaults.bold = 1; terminal->pvt->screen->defaults.half = 0; + return FALSE; } /* End modes. */ -static void +static gboolean vte_sequence_handler_me(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { vte_terminal_set_default_attributes(terminal); + return FALSE; } /* Half-bright on. */ -static void +static gboolean vte_sequence_handler_mh(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3204,40 +3270,44 @@ { terminal->pvt->screen->defaults.half = 1; terminal->pvt->screen->defaults.bold = 0; + return FALSE; } /* Invisible on. */ -static void +static gboolean vte_sequence_handler_mk(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.invisible = 1; + return FALSE; } /* Protect on. */ -static void +static gboolean vte_sequence_handler_mp(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.protect = 1; + return FALSE; } /* Reverse on. */ -static void +static gboolean vte_sequence_handler_mr(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.reverse = 1; + return FALSE; } /* Cursor right. */ -static void +static gboolean vte_sequence_handler_nd(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3249,40 +3319,42 @@ /* There's room to move right. */ screen->cursor_current.col++; } + return FALSE; } /* Move the cursor to the beginning of the next line, scrolling if necessary. */ -static void +static gboolean vte_sequence_handler_next_line(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->cursor_current.col = 0; - vte_sequence_handler_DO(terminal, match, match_quark, params); + return vte_sequence_handler_DO(terminal, match, match_quark, params); } /* No-op. */ -static void +static gboolean vte_sequence_handler_noop(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { + return FALSE; } /* Carriage return command(?). */ -static void +static gboolean vte_sequence_handler_nw(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_cr(terminal, match, match_quark, params); + return vte_sequence_handler_cr(terminal, match, match_quark, params); } /* Restore cursor (position). */ -static void +static gboolean vte_sequence_handler_rc(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3296,31 +3368,32 @@ screen->insert_delta, screen->insert_delta + terminal->row_count - 1); + return FALSE; } /* Cursor down, with scrolling. */ -static void +static gboolean vte_sequence_handler_reverse_index(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_sr(terminal, match, match_quark, params); + return vte_sequence_handler_sr(terminal, match, match_quark, params); } /* Cursor right N characters. */ -static void +static gboolean vte_sequence_handler_RI(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_nd); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_nd); } /* Save cursor (position). */ -static void +static gboolean vte_sequence_handler_sc(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3332,10 +3405,11 @@ screen->cursor_saved.row = CLAMP(screen->cursor_current.row - screen->insert_delta, 0, terminal->row_count - 1); + return FALSE; } /* Standout end. */ -static void +static gboolean vte_sequence_handler_se(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3402,10 +3476,11 @@ g_free(underline); } g_free(standout); + return FALSE; } /* Cursor down, with scrolling. */ -static void +static gboolean vte_sequence_handler_sf(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3489,21 +3564,22 @@ } /* Adjust the scrollbars if necessary. */ vte_terminal_adjust_adjustments(terminal, FALSE); + return FALSE; } /* Cursor down, with scrolling. */ -static void +static gboolean vte_sequence_handler_SF(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_sf); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_sf); } /* Standout start. */ -static void +static gboolean vte_sequence_handler_so(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3570,10 +3646,11 @@ g_free(underline); } g_free(standout); + return FALSE; } /* Cursor up, scrolling if need be. */ -static void +static gboolean vte_sequence_handler_sr(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3612,21 +3689,22 @@ vte_terminal_adjust_adjustments(terminal, FALSE); /* We modified the display, so make a note of it. */ terminal->pvt->text_modified_flag = TRUE; + return FALSE; } /* Cursor up, with scrolling. */ -static void +static gboolean vte_sequence_handler_SR(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_sr); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_sr); } /* Set tab stop in the current column. */ -static void +static gboolean vte_sequence_handler_st(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3638,10 +3716,11 @@ } vte_terminal_set_tabstop(terminal, terminal->pvt->screen->cursor_current.col); + return FALSE; } /* Tab. */ -static void +static gboolean vte_sequence_handler_ta(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3668,10 +3747,11 @@ } terminal->pvt->screen->cursor_current.col = newcol; + return FALSE; } /* Clear tabs selectively. */ -static void +static gboolean vte_sequence_handler_tab_clear(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3696,10 +3776,11 @@ terminal->pvt->tabstops = NULL; } } + return FALSE; } /* Move to status line. */ -static void +static gboolean vte_sequence_handler_ts(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3708,10 +3789,11 @@ terminal->pvt->screen->status_line = TRUE; g_string_truncate(terminal->pvt->screen->status_line_contents, 0); vte_terminal_emit_status_line_changed(terminal); + return FALSE; } /* Underline this character and move right. */ -static void +static gboolean vte_sequence_handler_uc(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3746,20 +3828,22 @@ /* We've modified the display without changing the text. Make a note * of it. */ terminal->pvt->text_modified_flag = TRUE; + return FALSE; } /* Underline end. */ -static void +static gboolean vte_sequence_handler_ue(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.underline = 0; + return FALSE; } /* Cursor up, no scrolling. */ -static void +static gboolean vte_sequence_handler_up(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3779,31 +3863,33 @@ } screen->cursor_current.row = MAX(screen->cursor_current.row - 1, start); + return FALSE; } /* Cursor up N lines, no scrolling. */ -static void +static gboolean vte_sequence_handler_UP(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_multiple(terminal, match, match_quark, params, - vte_sequence_handler_up); + return vte_sequence_handler_multiple(terminal, match, match_quark, + params, vte_sequence_handler_up); } /* Underline start. */ -static void +static gboolean vte_sequence_handler_us(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->screen->defaults.underline = 1; + return FALSE; } /* Visible bell. */ -static void +static gboolean vte_sequence_handler_vb(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3828,30 +3914,43 @@ vte_invalidate_all(terminal); gdk_window_process_updates(widget->window, TRUE); } + return FALSE; } /* Cursor visible. */ -static void +static gboolean vte_sequence_handler_ve(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->cursor_visible = TRUE; + return FALSE; +} + +/* Vertical tab. */ +static gboolean +vte_sequence_handler_vertical_tab(VteTerminal *terminal, + const char *match, + GQuark match_quark, + GValueArray *params) +{ + return vte_sequence_handler_index(terminal, match, match_quark, params); } /* Cursor invisible. */ -static void +static gboolean vte_sequence_handler_vi(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { terminal->pvt->cursor_visible = FALSE; + return FALSE; } /* Cursor standout. */ -static void +static gboolean vte_sequence_handler_vs(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3859,10 +3958,11 @@ { terminal->pvt->cursor_visible = TRUE; /* FIXME: should be *more* visible. */ + return FALSE; } /* Handle ANSI color setting and related stuffs (SGR). */ -static void +static gboolean vte_sequence_handler_character_attributes(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -3871,7 +3971,6 @@ unsigned int i; GValue *value; long param; - g_return_if_fail(VTE_IS_TERMINAL(terminal)); /* The default parameter is zero. */ param = 0; /* Step through each numeric parameter. */ @@ -4000,10 +4099,11 @@ terminal->pvt->screen->defaults.fore; terminal->pvt->screen->fill_defaults.back = terminal->pvt->screen->defaults.back; + return FALSE; } /* Clear above the current line. */ -static void +static gboolean vte_sequence_handler_clear_above_current(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4036,10 +4136,11 @@ } /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Clear the entire screen. */ -static void +static gboolean vte_sequence_handler_clear_screen(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4069,52 +4170,55 @@ vte_invalidate_all(terminal); /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Move the cursor to the given column, 1-based. */ -static void +static gboolean vte_sequence_handler_cursor_character_absolute(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_offset(terminal, match, match_quark, params, - -1, vte_sequence_handler_ch); + return vte_sequence_handler_offset(terminal, match, match_quark, params, + -1, vte_sequence_handler_ch); } /* Move the cursor to the given position, 1-based. */ -static void +static gboolean vte_sequence_handler_cursor_position(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_offset(terminal, match, match_quark, params, - -1, vte_sequence_handler_cm); + return vte_sequence_handler_offset(terminal, match, match_quark, params, + -1, vte_sequence_handler_cm); } /* Request terminal attributes. */ -static void +static gboolean vte_sequence_handler_request_terminal_parameters(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { vte_terminal_feed_child(terminal, "[?x", -1); + return FALSE; } /* Request terminal attributes. */ -static void +static gboolean vte_sequence_handler_return_terminal_status(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_terminal_feed_child(terminal, "xterm", -1); + vte_terminal_feed_child(terminal, "", -1); + return FALSE; } /* Send primary device attributes. */ -static void +static gboolean vte_sequence_handler_send_primary_device_attributes(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4122,23 +4226,24 @@ { /* Claim to be a VT220 with only national character set support. */ vte_terminal_feed_child(terminal, "[?60;9;c", -1); + return FALSE; } /* Send terminal ID. */ -static void +static gboolean vte_sequence_handler_return_terminal_id(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_send_primary_device_attributes(terminal, - match, - match_quark, - params); + return vte_sequence_handler_send_primary_device_attributes(terminal, + match, + match_quark, + params); } /* Send secondary device attributes. */ -static void +static gboolean vte_sequence_handler_send_secondary_device_attributes(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4156,13 +4261,14 @@ } g_strfreev(version); } - ret = g_strdup_printf("[>1;%ld;0c", ver); + ret = g_strdup_printf(_VTE_CAP_ESC "[>1;%ld;0c", ver); vte_terminal_feed_child(terminal, ret, -1); g_free(ret); + return FALSE; } /* Set icon/window titles. */ -static void +static gboolean vte_sequence_handler_set_title_internal(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4173,6 +4279,8 @@ VteConv conv; char *inbuf = NULL, *outbuf = NULL, *outbufptr = NULL, *title = NULL; gsize inbuf_len, outbuf_len; + gboolean ret = FALSE; + /* Get the string parameter's value. */ value = g_value_array_get_nth(params, 0); if (value) { @@ -4244,52 +4352,66 @@ } g_free(validated); g_free(title); + + ret = TRUE; } } + return ret; } /* Set one or the other. */ -static void +static gboolean vte_sequence_handler_set_icon_title(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_set_title_internal(terminal, match, match_quark, - params, "icon"); + return vte_sequence_handler_set_title_internal(terminal, + match, match_quark, + params, "icon"); } -static void +static gboolean vte_sequence_handler_set_window_title(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_set_title_internal(terminal, match, match_quark, - params, "window"); + return vte_sequence_handler_set_title_internal(terminal, + match, match_quark, + params, "window"); } /* Set both the window and icon titles to the same string. */ -static void +static gboolean vte_sequence_handler_set_icon_and_window_title(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_set_title_internal(terminal, match, match_quark, - params, "icon"); - vte_sequence_handler_set_title_internal(terminal, match, match_quark, - params, "window"); + int again; + again = 0; + if (vte_sequence_handler_set_title_internal(terminal, + match, match_quark, + params, "icon")) { + again++; + } + if (vte_sequence_handler_set_title_internal(terminal, + match, match_quark, + params, "window")) { + again++; + } + return (again > 0); } /* Restrict the scrolling region. */ -static void +static gboolean vte_sequence_handler_set_scrolling_region(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_offset(terminal, match, match_quark, params, - -1, vte_sequence_handler_cs); + return vte_sequence_handler_offset(terminal, match, match_quark, params, + -1, vte_sequence_handler_cs); } /* Show or hide the pointer. */ @@ -4344,14 +4466,14 @@ } /* Manipulate certain terminal attributes. */ -static void +static gboolean vte_sequence_handler_decset_internal(VteTerminal *terminal, int setting, gboolean restore, gboolean save, gboolean set) { - gboolean recognized = FALSE; + gboolean recognized = FALSE, again = FALSE; gpointer p; int i; struct { @@ -4510,8 +4632,6 @@ NULL, NULL}, }; - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - /* Handle the setting. */ for (i = 0; i < G_N_ELEMENTS(settings); i++) if (settings[i].setting == setting) { @@ -4604,11 +4724,14 @@ case 3: vte_terminal_emit_resize_window(terminal, (set ? 132 : 80) * - terminal->char_width, + terminal->char_width + + VTE_PAD_WIDTH * 2, terminal->row_count * - terminal->char_height); + terminal->char_height + + VTE_PAD_WIDTH * 2); /* Request a resize and redraw. */ vte_invalidate_all(terminal); + again = TRUE; break; case 5: /* Repaint everything in reverse mode. */ @@ -4754,10 +4877,11 @@ setting); } #endif + return again; } /* Set the application or normal keypad. */ -static void +static gboolean vte_sequence_handler_application_keypad(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4769,9 +4893,10 @@ } #endif terminal->pvt->keypad_mode = VTE_KEYMODE_APPLICATION; + return FALSE; } -static void +static gboolean vte_sequence_handler_normal_keypad(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4783,30 +4908,31 @@ } #endif terminal->pvt->keypad_mode = VTE_KEYMODE_NORMAL; + return FALSE; } /* Move the cursor. */ -static void +static gboolean vte_sequence_handler_character_position_absolute(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_offset(terminal, match, match_quark, params, - -1, vte_sequence_handler_ch); + return vte_sequence_handler_offset(terminal, match, match_quark, params, + -1, vte_sequence_handler_ch); } -static void +static gboolean vte_sequence_handler_line_position_absolute(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_offset(terminal, match, match_quark, params, - -1, vte_sequence_handler_cv); + return vte_sequence_handler_offset(terminal, match, match_quark, params, + -1, vte_sequence_handler_cv); } /* Toggle a terminal mode. */ -static void +static gboolean vte_sequence_handler_set_mode_internal(VteTerminal *terminal, long setting, gboolean value) { @@ -4825,58 +4951,67 @@ default: break; } + return FALSE; } /* Set certain terminal attributes. */ -static void +static gboolean vte_sequence_handler_set_mode(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - int i; + int i, again; long setting; GValue *value; if ((params == NULL) || (params->n_values == 0)) { - return; + return FALSE; } + again = 0; for (i = 0; i < params->n_values; i++) { value = g_value_array_get_nth(params, i); if (!G_VALUE_HOLDS_LONG(value)) { continue; } setting = g_value_get_long(value); - vte_sequence_handler_set_mode_internal(terminal, setting, - TRUE); + if (vte_sequence_handler_set_mode_internal(terminal, setting, + TRUE)) { + again++; + } } + return (again > 0); } /* Unset certain terminal attributes. */ -static void +static gboolean vte_sequence_handler_reset_mode(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - int i; + int i, again; long setting; GValue *value; if ((params == NULL) || (params->n_values == 0)) { - return; + return FALSE; } + again = 0; for (i = 0; i < params->n_values; i++) { value = g_value_array_get_nth(params, i); if (!G_VALUE_HOLDS_LONG(value)) { continue; } setting = g_value_get_long(value); - vte_sequence_handler_set_mode_internal(terminal, setting, - FALSE); + if (vte_sequence_handler_set_mode_internal(terminal, setting, + FALSE)) { + again++; + } } + return (again > 0); } /* Set certain terminal attributes. */ -static void +static gboolean vte_sequence_handler_decset(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4884,23 +5019,27 @@ { GValue *value; long setting; - int i; + int i, again; if ((params == NULL) || (params->n_values == 0)) { - return; + return FALSE; } + again = 0; for (i = 0; i < params->n_values; i++) { value = g_value_array_get_nth(params, i); if (!G_VALUE_HOLDS_LONG(value)) { continue; } setting = g_value_get_long(value); - vte_sequence_handler_decset_internal(terminal, setting, - FALSE, FALSE, TRUE); + if (vte_sequence_handler_decset_internal(terminal, setting, + FALSE, FALSE, TRUE)) { + again++; + } } + return (again > 0); } /* Unset certain terminal attributes. */ -static void +static gboolean vte_sequence_handler_decreset(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4908,33 +5047,37 @@ { GValue *value; long setting; - int i; + int i, again; if ((params == NULL) || (params->n_values == 0)) { - return; + return FALSE; } + again = 0; for (i = 0; i < params->n_values; i++) { value = g_value_array_get_nth(params, i); if (!G_VALUE_HOLDS_LONG(value)) { continue; } setting = g_value_get_long(value); - vte_sequence_handler_decset_internal(terminal, setting, - FALSE, FALSE, FALSE); + if (vte_sequence_handler_decset_internal(terminal, setting, + FALSE, FALSE, FALSE)) { + again++; + } } + return (again > 0); } /* Erase a specified number of characters. */ -static void +static gboolean vte_sequence_handler_erase_characters(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_ec(terminal, match, match_quark, params); + return vte_sequence_handler_ec(terminal, match, match_quark, params); } /* Erase certain lines in the display. */ -static void +static gboolean vte_sequence_handler_erase_in_display(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4943,6 +5086,7 @@ GValue *value; long param; int i; + gboolean again; /* The default parameter is 0. */ param = 0; /* Pull out a parameter. */ @@ -4954,37 +5098,40 @@ param = g_value_get_long(value); } /* Clear the right area. */ + again = FALSE; switch (param) { case 0: /* Clear below the current line. */ - vte_sequence_handler_cd(terminal, NULL, 0, NULL); + again = vte_sequence_handler_cd(terminal, NULL, 0, NULL); break; case 1: /* Clear above the current line. */ - vte_sequence_handler_clear_above_current(terminal, - NULL, - 0, - NULL); + again = vte_sequence_handler_clear_above_current(terminal, + NULL, + 0, + NULL); /* Clear everything to the left of the cursor, too. */ /* FIXME: vttest. */ - vte_sequence_handler_cb(terminal, NULL, 0, NULL); + again = vte_sequence_handler_cb(terminal, NULL, 0, NULL) || + again; break; case 2: /* Clear the entire screen. */ - vte_sequence_handler_clear_screen(terminal, - NULL, - 0, - NULL); + again = vte_sequence_handler_clear_screen(terminal, + NULL, + 0, + NULL); break; default: break; } /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return again; } /* Erase certain parts of the current line in the display. */ -static void +static gboolean vte_sequence_handler_erase_in_line(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -4993,6 +5140,7 @@ GValue *value; long param; int i; + gboolean again; /* The default parameter is 0. */ param = 0; /* Pull out a parameter. */ @@ -5004,49 +5152,52 @@ param = g_value_get_long(value); } /* Clear the right area. */ + again = FALSE; switch (param) { case 0: /* Clear to end of the line. */ - vte_sequence_handler_ce(terminal, NULL, 0, NULL); + again = vte_sequence_handler_ce(terminal, NULL, 0, NULL); break; case 1: /* Clear to start of the line. */ - vte_sequence_handler_cb(terminal, NULL, 0, NULL); + again = vte_sequence_handler_cb(terminal, NULL, 0, NULL); break; case 2: /* Clear the entire line. */ - vte_sequence_handler_clear_current_line(terminal, - NULL, 0, NULL); + again = vte_sequence_handler_clear_current_line(terminal, + NULL, 0, NULL); break; default: break; } /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return again; } /* Perform a full-bore reset. */ -static void +static gboolean vte_sequence_handler_full_reset(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { vte_terminal_reset(terminal, TRUE, TRUE); + return FALSE; } /* Insert a specified number of blank characters. */ -static void +static gboolean vte_sequence_handler_insert_blank_characters(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { - vte_sequence_handler_IC(terminal, match, match_quark, params); + return vte_sequence_handler_IC(terminal, match, match_quark, params); } /* Insert a certain number of lines below the current cursor. */ -static void +static gboolean vte_sequence_handler_insert_lines(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5091,10 +5242,11 @@ vte_terminal_adjust_adjustments(terminal, FALSE); /* We've modified the display. Make a note of it. */ terminal->pvt->text_inserted_count++; + return FALSE; } /* Delete certain lines from the scrolling region. */ -static void +static gboolean vte_sequence_handler_delete_lines(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5140,10 +5292,11 @@ vte_terminal_adjust_adjustments(terminal, FALSE); /* We've modified the display. Make a note of it. */ terminal->pvt->text_deleted_count++; + return FALSE; } /* Set the terminal encoding. */ -static void +static gboolean vte_sequence_handler_local_charset(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5152,20 +5305,22 @@ G_CONST_RETURN char *locale_encoding; g_get_charset(&locale_encoding); vte_terminal_set_encoding(terminal, locale_encoding); + return FALSE; } -static void +static gboolean vte_sequence_handler_utf_8_charset(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { vte_terminal_set_encoding(terminal, "UTF-8"); + return FALSE; } /* Device status reports. The possible reports are the cursor position and * whether or not we're okay. */ -static void +static gboolean vte_sequence_handler_device_status_report(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5200,10 +5355,11 @@ break; } } + return FALSE; } /* DEC-style device status reports. */ -static void +static gboolean vte_sequence_handler_dec_device_status_report(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5251,10 +5407,11 @@ break; } } + return FALSE; } /* Restore a certain terminal attribute. */ -static void +static gboolean vte_sequence_handler_restore_mode(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5262,23 +5419,27 @@ { GValue *value; long setting; - int i; + int i, again; if ((params == NULL) || (params->n_values == 0)) { - return; + return FALSE; } + again = 0; for (i = 0; i < params->n_values; i++) { value = g_value_array_get_nth(params, i); if (!G_VALUE_HOLDS_LONG(value)) { continue; } setting = g_value_get_long(value); - vte_sequence_handler_decset_internal(terminal, setting, - TRUE, FALSE, FALSE); + if (vte_sequence_handler_decset_internal(terminal, setting, + TRUE, FALSE, FALSE)) { + again++; + } } + return (again > 0); } /* Save a certain terminal attribute. */ -static void +static gboolean vte_sequence_handler_save_mode(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5286,24 +5447,28 @@ { GValue *value; long setting; - int i; + int i, again; if ((params == NULL) || (params->n_values == 0)) { - return; + return FALSE; } + again = 0; for (i = 0; i < params->n_values; i++) { value = g_value_array_get_nth(params, i); if (!G_VALUE_HOLDS_LONG(value)) { continue; } setting = g_value_get_long(value); - vte_sequence_handler_decset_internal(terminal, setting, - FALSE, TRUE, FALSE); + if (vte_sequence_handler_decset_internal(terminal, setting, + FALSE, TRUE, FALSE)) { + again++; + } } + return (again > 0); } /* Perform a screen alignment test -- fill all visible cells with the * letter "E". */ -static void +static gboolean vte_sequence_handler_screen_alignment_test(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5342,22 +5507,24 @@ /* We modified the display, so make a note of it for completeness. */ terminal->pvt->text_modified_flag = TRUE; + return FALSE; } /* Perform a soft reset. */ -static void +static gboolean vte_sequence_handler_soft_reset(VteTerminal *terminal, const char *match, GQuark match_quark, GValueArray *params) { vte_terminal_reset(terminal, FALSE, FALSE); + return FALSE; } /* Window manipulation control sequences. Most of these are considered * bad ideas, but they're implemented as signals which the application * is free to ignore, so they're harmless. */ -static void +static gboolean vte_sequence_handler_window_manipulation(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5435,8 +5602,10 @@ } #endif vte_terminal_emit_resize_window(terminal, - arg2, - arg1); + arg2 + + VTE_PAD_WIDTH * 2, + arg1 + + VTE_PAD_WIDTH * 2); i += 2; } break; @@ -5475,8 +5644,10 @@ } #endif vte_terminal_emit_resize_window(terminal, - arg2 * terminal->char_width, - arg1 * terminal->char_height); + arg2 * terminal->char_width + + VTE_PAD_WIDTH * 2, + arg1 * terminal->char_height + + VTE_PAD_WIDTH * 2); i += 2; } break; @@ -5627,16 +5798,19 @@ /* Resize to the specified number of * rows. */ vte_terminal_emit_resize_window(terminal, - terminal->column_count * terminal->char_width, - param * terminal->char_height); + terminal->column_count * terminal->char_width + + VTE_PAD_WIDTH * 2, + param * terminal->char_height + + VTE_PAD_WIDTH * 2); } break; } } + return TRUE; } /* Complain that we got an escape sequence that's actually a keystroke. */ -static void +static gboolean vte_sequence_handler_complain_key(VteTerminal *terminal, const char *match, GQuark match_quark, @@ -5644,6 +5818,7 @@ { g_warning(_("Got unexpected (key?) sequence `%s'."), match ? match : "???"); + return FALSE; } /* The table of handlers. Primarily used at initialization time. */ @@ -6004,6 +6179,7 @@ {"erase-characters", vte_sequence_handler_erase_characters}, {"erase-in-display", vte_sequence_handler_erase_in_display}, {"erase-in-line", vte_sequence_handler_erase_in_line}, + {"form-feed", vte_sequence_handler_form_feed}, {"full-reset", vte_sequence_handler_full_reset}, {"horizontal-and-vertical-position", vte_sequence_handler_horizontal_and_vertical_position}, {"index", vte_sequence_handler_index}, @@ -6016,6 +6192,7 @@ {"invoke-g3-character-set-as-gr", NULL}, {"invoke-g3-character-set", NULL}, {"iso8859-1-character-set", vte_sequence_handler_local_charset}, + {"linux-console-cursor-attributes", vte_sequence_handler_noop}, {"line-position-absolute", vte_sequence_handler_line_position_absolute}, {"media-copy", NULL}, {"memory-lock", NULL}, @@ -6058,6 +6235,7 @@ {"tab-clear", vte_sequence_handler_tab_clear}, {"tab-set", vte_sequence_handler_st}, {"utf-8-character-set", vte_sequence_handler_utf_8_charset}, + {"vertical-tab", vte_sequence_handler_vertical_tab}, {"window-manipulation", vte_sequence_handler_window_manipulation}, }; @@ -6222,6 +6400,56 @@ } /** + * vte_terminal_set_color_cursor + * @terminal: a #VteTerminal + * @background: the new color to use for the text cursor + * + * Sets the background color for text which is under the cursor. If NULL, text + * under the cursor will be drawn with foreground and background colors + * reversed. + * + * Since: 0.11.11 + * + */ +void +vte_terminal_set_color_cursor(VteTerminal *terminal, + const GdkColor *cursor_background) +{ + if (cursor_background != NULL) { + vte_terminal_set_color_internal(terminal, VTE_CUR_BG, + cursor_background); + terminal->pvt->cursor_color_set = TRUE; + } else { + terminal->pvt->cursor_color_set = FALSE; + } +} + +/** + * vte_terminal_set_color_highlight + * @terminal: a #VteTerminal + * @background: the new color to use for highlighted text + * + * Sets the background color for text which is highlighted. If NULL, + * highlighted text (which is usually highlighted because it is selected) will + * be drawn with foreground and background colors reversed. + * + * Since: 0.11.11 + * + */ +void +vte_terminal_set_color_highlight(VteTerminal *terminal, + const GdkColor *highlight_background) +{ + if (highlight_background != NULL) { + vte_terminal_set_color_internal(terminal, VTE_DEF_HL, + highlight_background); + terminal->pvt->highlight_color_set = TRUE; + } else { + terminal->pvt->highlight_color_set = FALSE; + } +} + +/** * vte_terminal_set_colors * @terminal: a #VteTerminal * @foreground: the new foreground color, or #NULL @@ -6306,6 +6534,16 @@ 0.5, &color); break; + case VTE_DEF_HL: + color.red = 0xc000; + color.blue = 0xc000; + color.green = 0xc000; + break; + case VTE_CUR_BG: + color.red = 0x0000; + color.blue = 0x0000; + color.green = 0x0000; + break; case 0 + 0: case 0 + 1: case 0 + 2: @@ -6620,7 +6858,7 @@ #endif /* Handle a terminal control sequence and its parameters. */ -static void +static gboolean vte_terminal_handle_sequence(GtkWidget *widget, const char *match_s, GQuark match, @@ -6630,9 +6868,10 @@ VteTerminalSequenceHandler handler; VteScreen *screen; struct vte_cursor_position position; + gboolean ret; - g_return_if_fail(widget != NULL); - g_return_if_fail(VTE_IS_TERMINAL(widget)); + g_return_val_if_fail(widget != NULL, FALSE); + g_return_val_if_fail(VTE_IS_TERMINAL(widget), FALSE); terminal = VTE_TERMINAL(widget); screen = terminal->pvt->screen; @@ -6653,16 +6892,19 @@ #endif if (handler != NULL) { /* Let the handler handle it. */ - handler(terminal, match_s, match, params); + ret = handler(terminal, match_s, match, params); } else { g_warning(_("No handler for control sequence `%s' defined."), match_s); + ret = FALSE; } /* Let the updating begin. */ if (GTK_WIDGET_REALIZED (widget)) { gdk_window_thaw_updates(widget->window); } + + return ret; } /* Catch a VteReaper child-exited signal, and if it matches the one we're @@ -6790,29 +7032,12 @@ } } -/** - * vte_terminal_fork_command: - * @terminal: a #VteTerminal - * @command: the name of a binary to run - * @argv: the argument list to be passed to @command - * @envv: a list of environment variables to be added to the environment before - * starting @command - * @directory: the name of a directory the command should start in, or NULL - * @lastlog: TRUE if the session should be logged to the lastlog - * @utmp: TRUE if the session should be logged to the utmp/utmpx log - * @wtmp: TRUE if the session should be logged to the wtmp/wtmpx log - * - * Starts the specified command under a newly-allocated controlling - * pseudo-terminal. TERM is automatically set to reflect the terminal widget's - * emulation setting. If @lastlog, @utmp, or @wtmp are TRUE, logs the session - * to the specified system log files. - * - * Returns: the ID of the new process - */ -pid_t -vte_terminal_fork_command(VteTerminal *terminal, const char *command, - char **argv, char **envv, const char *directory, - gboolean lastlog, gboolean utmp, gboolean wtmp) +/* Basic wrapper around _vte_pty_open, which handles the pipefitting. */ +static pid_t +_vte_terminal_fork_basic(VteTerminal *terminal, const char *command, + char **argv, char **envv, + const char *directory, + gboolean lastlog, gboolean utmp, gboolean wtmp) { char **env_add; int i; @@ -6820,45 +7045,43 @@ GtkWidget *widget; VteReaper *reaper; - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); widget = GTK_WIDGET(terminal); - /* Start up the command and get the PTY of the master. */ - for (i = 0; (envv != NULL) && (envv[i] != NULL); i++) ; - - env_add = g_malloc0(sizeof(char*) * (i + 2)); - if (command == NULL) { - command = terminal->pvt->shell; + /* Duplicate the environment, and add one more variable. */ + for (i = 0; (envv != NULL) && (envv[i] != NULL); i++) { + /* nothing */ ; } - + env_add = g_malloc0(sizeof(char*) * (i + 2)); env_add[0] = g_strdup_printf("TERM=%s", terminal->pvt->emulation); for (i = 0; (envv != NULL) && (envv[i] != NULL); i++) { env_add[i + 1] = g_strdup(envv[i]); } env_add[i + 1] = NULL; + /* Close any existing ptys. */ if (terminal->pvt->pty_master != -1) { _vte_pty_close(terminal->pvt->pty_master); close(terminal->pvt->pty_master); } - terminal->pvt->pty_master = _vte_pty_open(&pid, - env_add, - command, - argv, - directory, - terminal->column_count, - terminal->row_count, - lastlog, - utmp, - wtmp); - for (i = 0; env_add[i] != NULL; i++) { - g_free(env_add[i]); + /* Open the new pty. */ + pid = -1; + i = _vte_pty_open(&pid, env_add, command, argv, directory, + terminal->column_count, terminal->row_count, + lastlog, utmp, wtmp); + switch (i) { + case -1: + return -1; + break; + default: + if (pid != 0) { + terminal->pvt->pty_master = i; + } } - g_free(env_add); - /* If we started the process, set up to listen for its output. */ - if (pid != -1) { + /* If we successfully started the process, set up to listen for its + * output. */ + if ((pid != -1) && (pid != 0)) { /* Set this as the child's pid. */ terminal->pvt->pty_pid = pid; @@ -6892,10 +7115,89 @@ _vte_terminal_connect_pty_read(terminal); } + /* Clean up. */ + for (i = 0; env_add[i] != NULL; i++) { + g_free(env_add[i]); + } + g_free(env_add); + /* Return the pid to the caller. */ return pid; } +/** + * vte_terminal_fork_command: + * @terminal: a #VteTerminal + * @command: the name of a binary to run + * @argv: the argument list to be passed to @command + * @envv: a list of environment variables to be added to the environment before + * starting @command, or NULL + * @directory: the name of a directory the command should start in, or NULL + * @lastlog: TRUE if the session should be logged to the lastlog + * @utmp: TRUE if the session should be logged to the utmp/utmpx log + * @wtmp: TRUE if the session should be logged to the wtmp/wtmpx log + * + * Starts the specified command under a newly-allocated controlling + * pseudo-terminal. TERM is automatically set to reflect the terminal widget's + * emulation setting. If @lastlog, @utmp, or @wtmp are TRUE, logs the session + * to the specified system log files. + * + * Returns: the ID of the new process + */ +pid_t +vte_terminal_fork_command(VteTerminal *terminal, + const char *command, char **argv, char **envv, + const char *directory, + gboolean lastlog, gboolean utmp, gboolean wtmp) +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); + + /* Make the user's shell the default command. */ + if (command == NULL) { + command = terminal->pvt->shell; + } + + /* Start up the command and get the PTY of the master. */ + return _vte_terminal_fork_basic(terminal, command, argv, envv, + directory, lastlog, utmp, wtmp); +} + +/** + * vte_terminal_forkpty: + * @terminal: a #VteTerminal + * @envv: a list of environment variables to be added to the environment before + * starting returning in the child process, or NULL + * @directory: the name of a directory the child process should change to, or + * NULL + * @lastlog: TRUE if the session should be logged to the lastlog + * @utmp: TRUE if the session should be logged to the utmp/utmpx log + * @wtmp: TRUE if the session should be logged to the wtmp/wtmpx log + * + * Starts a new child process under a newly-allocated controlling + * pseudo-terminal. TERM is automatically set to reflect the terminal widget's + * emulation setting. If @lastlog, @utmp, or @wtmp are TRUE, logs the session + * to the specified system log files. + * + * Returns: the ID of the new process in the parent, 0 in the child, and -1 if + * there was an error + * + * Since: 0.11.11 + */ +pid_t +vte_terminal_forkpty(VteTerminal *terminal, + char **envv, const char *directory, + gboolean lastlog, gboolean utmp, gboolean wtmp) +{ + pid_t ret; + + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); + + ret = _vte_terminal_fork_basic(terminal, NULL, NULL, envv, + directory, lastlog, utmp, wtmp); + + return ret; +} + /* Handle an EOF from the client. */ static void vte_terminal_eof(GIOChannel *channel, gpointer data) @@ -6951,6 +7253,10 @@ g_free(terminal->pvt->im_preedit); terminal->pvt->im_preedit = NULL; } + if (terminal->pvt->im_preedit_attrs != NULL) { + pango_attr_list_unref(terminal->pvt->im_preedit_attrs); + terminal->pvt->im_preedit_attrs = NULL; + } } } @@ -7034,7 +7340,7 @@ const char *match; GQuark quark; const gunichar *next; - gboolean leftovers, modified, bottom, inserted; + gboolean leftovers, modified, bottom, inserted, again; GArray *unichars; g_return_val_if_fail(GTK_IS_WIDGET(data), FALSE); @@ -7069,7 +7375,8 @@ terminal->pvt->text_deleted_count = 0; /* We should only be called when there's data to process. */ - g_assert(_vte_buffer_length(terminal->pvt->incoming) > 0); + g_assert((_vte_buffer_length(terminal->pvt->incoming) > 0) || + (terminal->pvt->pending->len > 0)); /* Convert the data into unicode characters. */ unichars = terminal->pvt->pending; @@ -7083,9 +7390,9 @@ /* Try initial substrings. */ start = 0; - modified = leftovers = inserted = FALSE; + modified = leftovers = inserted = again = FALSE; - while ((start < wcount) && !leftovers) { + while ((start < wcount) && !leftovers && !again) { /* Try to match any control sequences. */ _vte_matcher_match(terminal->pvt->matcher, &wbuf[start], @@ -7109,10 +7416,10 @@ vte_terminal_emit_pending_text_signals(terminal, quark); /* Call the right sequence handler for the requested * behavior. */ - vte_terminal_handle_sequence(GTK_WIDGET(terminal), - match, - quark, - params); + again = vte_terminal_handle_sequence(GTK_WIDGET(terminal), + match, + quark, + params); /* Skip over the proper number of unicode chars. */ start = (next - wbuf); /* Flush any pending signals. */ @@ -7259,6 +7566,10 @@ terminal->pvt->pending = unichars; } else { g_array_set_size(terminal->pvt->pending, 0); + /* If we're out of data, we needn't pause to let the + * controlling application respond to incoming data, because + * the main loop is already going to do that. */ + again = FALSE; } /* Flush any pending "inserted" signals. */ @@ -7295,6 +7606,7 @@ if (modified || (screen != terminal->pvt->screen)) { /* Signal that the visible contents changed. */ vte_terminal_match_contents_clear(terminal); + vte_terminal_emit_contents_changed(terminal); } if ((cursor.col != terminal->pvt->screen->cursor_current.col) || @@ -7324,11 +7636,13 @@ } #endif /* Disconnect this function from the main loop. */ - terminal->pvt->processing = FALSE; - if (terminal->pvt->processing_tag != VTE_INVALID_SOURCE) { - g_source_remove(terminal->pvt->processing_tag); + if (!again) { + terminal->pvt->processing = FALSE; + if (terminal->pvt->processing_tag != VTE_INVALID_SOURCE) { + g_source_remove(terminal->pvt->processing_tag); + } + terminal->pvt->processing_tag = VTE_INVALID_SOURCE; } - terminal->pvt->processing_tag = VTE_INVALID_SOURCE; #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_IO)) { @@ -7743,7 +8057,7 @@ fprintf(stderr, "Input method pre-edit ended.\n"); } #endif - terminal->pvt->im_preedit_active = TRUE; + terminal->pvt->im_preedit_active = FALSE; } /* The pre-edit string changed. */ @@ -7771,11 +8085,16 @@ * for repainting. */ vte_invalidate_cursor_once(terminal, FALSE); - pango_attr_list_unref(attrs); if (terminal->pvt->im_preedit != NULL) { g_free(terminal->pvt->im_preedit); } terminal->pvt->im_preedit = str; + + if (terminal->pvt->im_preedit_attrs != NULL) { + pango_attr_list_unref(terminal->pvt->im_preedit_attrs); + } + terminal->pvt->im_preedit_attrs = attrs; + terminal->pvt->im_preedit_cursor = cursor; vte_invalidate_cursor_once(terminal, FALSE); @@ -7786,6 +8105,8 @@ vte_terminal_configure_toplevel(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { + VteTerminal *terminal; + #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_EVENTS)) { fprintf(stderr, "Top level parent configured.\n"); @@ -7794,10 +8115,14 @@ g_return_val_if_fail(GTK_IS_WIDGET(widget), FALSE); g_return_val_if_fail(GTK_WIDGET_TOPLEVEL(widget), FALSE); g_return_val_if_fail(VTE_IS_TERMINAL(data), FALSE); + terminal = VTE_TERMINAL(data); - /* In case we were resized, repaint everything, including any border - * regions which no cell covers. */ - vte_invalidate_all(VTE_TERMINAL(data)); + if (terminal->pvt->bg_transparent) { + /* We have to repaint the entire window, because we don't get + * an expose event unless some portion of our visible area + * moved out from behind another window. */ + vte_invalidate_all(terminal); + } return FALSE; } @@ -7845,7 +8170,8 @@ if (pango_font_description_equal(style->font_desc, widget->style->font_desc) || (terminal->pvt->fontdesc == NULL)) { - vte_terminal_set_font(terminal, terminal->pvt->fontdesc); + vte_terminal_set_font_full(terminal, terminal->pvt->fontdesc, + terminal->pvt->fontantialias); } } @@ -7869,11 +8195,22 @@ gunichar keychar = 0; char keybuf[VTE_UTF8_BPC]; GdkModifierType modifiers; + GtkWidgetClass *widget_class; g_return_val_if_fail(widget != NULL, TRUE); g_return_val_if_fail(VTE_IS_TERMINAL(widget), TRUE); terminal = VTE_TERMINAL(widget); + /* First, check if GtkWidget's behavior already does something with + * this key. */ + widget_class = g_type_class_peek(GTK_TYPE_WIDGET); + if (GTK_WIDGET_CLASS(widget_class)->key_press_event) { + if ((GTK_WIDGET_CLASS(widget_class))->key_press_event(widget, + event)) { + return TRUE; + } + } + /* If it's a keypress, record that we got the event, in case the * input method takes the event from us. */ if (event->type == GDK_KEY_PRESS) { @@ -7922,19 +8259,48 @@ #endif /* We steal many keypad keys here. */ - switch (keyval) { - case GDK_KP_Add: - case GDK_KP_Subtract: - case GDK_KP_Multiply: - case GDK_KP_Divide: - case GDK_KP_Enter: - steal = TRUE; - break; - default: - break; - } - if (modifiers & VTE_META_MASK) { - steal = TRUE; + if (!terminal->pvt->im_preedit_active) { + switch (keyval) { + case GDK_KP_Add: + case GDK_KP_Subtract: + case GDK_KP_Multiply: + case GDK_KP_Divide: + case GDK_KP_Enter: + steal = TRUE; + break; + default: + break; + } + if (modifiers & VTE_META_MASK) { + steal = TRUE; + } + switch (keyval) { + case GDK_Multi_key: + case GDK_Codeinput: + case GDK_SingleCandidate: + case GDK_MultipleCandidate: + case GDK_PreviousCandidate: + case GDK_Kanji: + case GDK_Muhenkan: + case GDK_Henkan: + case GDK_Romaji: + case GDK_Hiragana: + case GDK_Katakana: + case GDK_Hiragana_Katakana: + case GDK_Zenkaku: + case GDK_Hankaku: + case GDK_Zenkaku_Hankaku: + case GDK_Touroku: + case GDK_Massyo: + case GDK_Kana_Lock: + case GDK_Kana_Shift: + case GDK_Eisu_Shift: + case GDK_Eisu_toggle: + steal = FALSE; + break; + default: + break; + } } } @@ -7993,11 +8359,11 @@ case GDK_Delete: switch (terminal->pvt->delete_binding) { case VTE_ERASE_ASCII_BACKSPACE: - normal = g_strdup(""); + normal = g_strdup("\010"); normal_length = 1; break; case VTE_ERASE_ASCII_DELETE: - normal = g_strdup(""); + normal = g_strdup("\177"); normal_length = 1; break; case VTE_ERASE_DELETE_SEQUENCE: @@ -8141,7 +8507,9 @@ !suppress_meta_esc && (normal_length > 0) && (terminal->pvt->modifiers & VTE_META_MASK)) { - vte_terminal_feed_child(terminal, "", 1); + vte_terminal_feed_child(terminal, + _VTE_CAP_ESC, + 1); } if (normal_length > 0) { vte_terminal_feed_child_using_modes(terminal, @@ -8754,6 +9122,7 @@ gpointer data, GArray *attributes) { + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); return vte_terminal_get_text_range_maybe_wrapped(terminal, start_row, start_col, end_row, end_col, @@ -8776,7 +9145,7 @@ GArray *attributes) { long col, row, last_space, last_spacecol, - last_nonspace, last_nonspacecol; + last_nonspace, last_nonspacecol, line_start; VteScreen *screen; struct vte_charcell *pcell = NULL; GString *string; @@ -8796,6 +9165,7 @@ last_space = last_nonspace = -1; last_spacecol = last_nonspacecol = -1; attr.row = row; + line_start = string->len; pcell = NULL; do { /* If it's not part of a multi-column character, @@ -8883,6 +9253,11 @@ g_string_truncate(string, last_nonspace + 1); } } + /* If we found no non-whitespace characters on this line, trim + * it, as xterm does. */ + if (last_nonspacecol == -1) { + g_string_truncate(string, line_start); + } /* Make sure that the attributes array is as long as the * string. */ if (attributes) { @@ -8979,6 +9354,7 @@ gpointer data, GArray *attributes) { + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); return vte_terminal_get_text_maybe_wrapped(terminal, TRUE, is_selected ? @@ -9090,14 +9466,11 @@ /* Start selection at the location of the event. */ static void -vte_terminal_start_selection(GtkWidget *widget, GdkEventButton *event, +vte_terminal_start_selection(VteTerminal *terminal, GdkEventButton *event, enum vte_selection_type selection_type) { - VteTerminal *terminal; long cellx, celly, delta; - terminal = VTE_TERMINAL(widget); - /* Convert the event coordinates to cell coordinates. */ delta = terminal->pvt->screen->scroll_delta; cellx = (event->x - VTE_PAD_WIDTH) / terminal->char_width; @@ -9158,18 +9531,17 @@ /* Extend selection to include the given event coordinates. */ static void -vte_terminal_extend_selection(GtkWidget *widget, double x, double y, +vte_terminal_extend_selection(VteTerminal *terminal, double x, double y, gboolean always_grow) { - VteTerminal *terminal; VteScreen *screen; VteRowData *rowdata; long delta, height, width, last_nonspace, i, j; struct vte_charcell *cell; struct selection_event_coords *origin, *last, *start, *end; struct selection_cell_coords old_start, old_end, *sc, *ec, tc; + gboolean invalidate_selected = FALSE; - terminal = VTE_TERMINAL(widget); screen = terminal->pvt->screen; old_start = terminal->pvt->selection_start; old_end = terminal->pvt->selection_end; @@ -9183,6 +9555,7 @@ * the selected block. */ if (terminal->pvt->selecting_restart) { vte_terminal_deselect_all(terminal); + invalidate_selected = TRUE; /* Record the origin of the selection. */ terminal->pvt->selection_origin = terminal->pvt->selection_restart_origin; @@ -9489,6 +9862,26 @@ ABS(old_end.y - terminal->pvt->selection_end.y) + 1); } + if (invalidate_selected) { +#ifdef VTE_DEBUG + if (_vte_debug_on(VTE_DEBUG_SELECTION)) { + fprintf(stderr, "Refreshing lines %ld to %ld.\n", + MIN(terminal->pvt->selection_start.y, + terminal->pvt->selection_end.y), + MAX(terminal->pvt->selection_start.y, + terminal->pvt->selection_end.y)); + } +#endif + vte_invalidate_cells(terminal, + 0, + terminal->column_count, + MIN(terminal->pvt->selection_start.y, + terminal->pvt->selection_end.y), + MAX(terminal->pvt->selection_start.y, + terminal->pvt->selection_end.y) - + MIN(terminal->pvt->selection_start.y, + terminal->pvt->selection_end.y) + 1); + } #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_SELECTION)) { @@ -9566,7 +9959,7 @@ x = terminal->column_count * terminal->char_width; } /* Extend selection to cover the newly-scrolled area. */ - vte_terminal_extend_selection(widget, x, y, FALSE); + vte_terminal_extend_selection(terminal, x, y, FALSE); } else { /* Stop autoscrolling. */ terminal->pvt->mouse_autoscroll_tag = 0; @@ -9641,7 +10034,7 @@ #endif if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || !event_mode) { - vte_terminal_extend_selection(widget, + vte_terminal_extend_selection(terminal, event->x - VTE_PAD_WIDTH, event->y - VTE_PAD_WIDTH, FALSE); @@ -9755,12 +10148,11 @@ start_selecting = TRUE; } } else { - /* If the user hit shift, and the location - * clicked isn't selected, and we already have - * a selection, extend selection, otherwise - * start over. */ + /* If the user hit shift, then extend the + * selection instead. */ if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) && - terminal->pvt->has_selection && + (terminal->pvt->has_selection || + terminal->pvt->selecting_restart) && !vte_cell_is_selected(terminal, cellx, celly, @@ -9772,16 +10164,16 @@ } if (start_selecting) { vte_terminal_deselect_all(terminal); - vte_terminal_start_selection(widget, + vte_terminal_start_selection(terminal, event, selection_type_char); handled = TRUE; } if (extend_selecting) { - vte_terminal_extend_selection(widget, + vte_terminal_extend_selection(terminal, event->x - VTE_PAD_WIDTH, event->y - VTE_PAD_WIDTH, - TRUE); + !terminal->pvt->selecting_restart); handled = TRUE; } break; @@ -9819,10 +10211,10 @@ case 1: if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || !event_mode) { - vte_terminal_start_selection(widget, + vte_terminal_start_selection(terminal, event, selection_type_word); - vte_terminal_extend_selection(widget, + vte_terminal_extend_selection(terminal, event->x - VTE_PAD_WIDTH, event->y - VTE_PAD_WIDTH, FALSE); @@ -9848,10 +10240,10 @@ case 1: if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || !event_mode) { - vte_terminal_start_selection(widget, + vte_terminal_start_selection(terminal, event, selection_type_line); - vte_terminal_extend_selection(widget, + vte_terminal_extend_selection(terminal, event->x - VTE_PAD_WIDTH, event->y - VTE_PAD_WIDTH, FALSE); @@ -10089,9 +10481,10 @@ } /** - * vte_terminal_set_font: + * vte_terminal_set_font_full: * @terminal: a #VteTerminal * @font_desc: The #PangoFontDescription of the desired font. + * @anti_alias: Specify if anti aliasing of the fonts is to be used or not. * * Sets the font used for rendering all text displayed by the terminal, * overriding any fonts set using gtk_widget_modify_font(). The terminal @@ -10099,10 +10492,12 @@ * metrics, and attempt to resize itself to keep the same number of rows * and columns. * + * Since: 0.11.11 */ void -vte_terminal_set_font(VteTerminal *terminal, - const PangoFontDescription *font_desc) +vte_terminal_set_font_full(VteTerminal *terminal, + const PangoFontDescription *font_desc, + VteTerminalAntiAlias anti_alias) { GtkWidget *widget; PangoFontDescription *desc; @@ -10133,15 +10528,19 @@ } #endif } + terminal->pvt->fontantialias = anti_alias; /* Free the old font description and save the new one. */ if (terminal->pvt->fontdesc != NULL) { pango_font_description_free(terminal->pvt->fontdesc); } terminal->pvt->fontdesc = desc; + terminal->pvt->fontantialias = anti_alias; /* Set the drawing font. */ - _vte_draw_set_text_font(terminal->pvt->draw, terminal->pvt->fontdesc); + _vte_draw_set_text_font(terminal->pvt->draw, + terminal->pvt->fontdesc, + anti_alias); vte_terminal_apply_metrics(terminal, _vte_draw_get_text_width(terminal->pvt->draw), _vte_draw_get_text_height(terminal->pvt->draw), @@ -10153,16 +10552,39 @@ } /** - * vte_terminal_set_font_from_string: + * vte_terminal_set_font: + * @terminal: a #VteTerminal + * @font_desc: The #PangoFontDescription of the desired font. + * + * Sets the font used for rendering all text displayed by the terminal, + * overriding any fonts set using gtk_widget_modify_font(). The terminal + * will immediately attempt to load the desired font, retrieve its + * metrics, and attempt to resize itself to keep the same number of rows + * and columns. + * + */ +void +vte_terminal_set_font(VteTerminal *terminal, + const PangoFontDescription *font_desc) +{ + vte_terminal_set_font_full(terminal, font_desc, + VTE_ANTI_ALIAS_USE_DEFAULT); +} + +/** + * vte_terminal_set_font_from_string_full: * @terminal: a #VteTerminal * @name: A string describing the font. + * @antialias: Whether or not to antialias the font (if possible). * * A convenience function which converts @name into a #PangoFontDescription and - * passes it to vte_terminal_set_font(). + * passes it to vte_terminal_set_font_full(). * + * Since: 0.11.11 */ void -vte_terminal_set_font_from_string(VteTerminal *terminal, const char *name) +vte_terminal_set_font_from_string_full(VteTerminal *terminal, const char *name, + VteTerminalAntiAlias antialias) { PangoFontDescription *font_desc; g_return_if_fail(VTE_IS_TERMINAL(terminal)); @@ -10170,11 +10592,27 @@ g_return_if_fail(strlen(name) > 0); font_desc = pango_font_description_from_string(name); - vte_terminal_set_font(terminal, font_desc); + vte_terminal_set_font_full(terminal, font_desc, antialias); pango_font_description_free(font_desc); } /** + * vte_terminal_set_font_from_string: + * @terminal: a #VteTerminal + * @name: A string describing the font. + * + * A convenience function which converts @name into a #PangoFontDescription and + * passes it to vte_terminal_set_font(). + * + */ +void +vte_terminal_set_font_from_string(VteTerminal *terminal, const char *name) +{ + vte_terminal_set_font_from_string_full(terminal, name, + VTE_ANTI_ALIAS_USE_DEFAULT); +} + +/** * vte_terminal_get_font: * @terminal: a #VteTerminal * @@ -10440,6 +10878,9 @@ terminal->pvt->flags.ul = _vte_termcap_find_boolean(terminal->pvt->termcap, terminal->pvt->emulation, "ul"); + terminal->pvt->flags.xn = _vte_termcap_find_boolean(terminal->pvt->termcap, + terminal->pvt->emulation, + "xn"); /* Resize to the given default. */ columns = _vte_termcap_find_numeric(terminal->pvt->termcap, @@ -10558,7 +10999,8 @@ spec->name); } #endif - vte_terminal_set_font(terminal, terminal->pvt->fontdesc); + vte_terminal_set_font_full(terminal, terminal->pvt->fontdesc, + terminal->pvt->fontantialias); } /* Connect to notifications from our settings object that font hints have @@ -10679,6 +11121,7 @@ pvt->flags.am = FALSE; pvt->flags.bw = FALSE; pvt->flags.ul = FALSE; + pvt->flags.xn = FALSE; pvt->keypad_mode = VTE_KEYMODE_NORMAL; pvt->cursor_mode = VTE_KEYMODE_NORMAL; pvt->sun_fkey_mode = FALSE; @@ -10856,20 +11299,23 @@ /* Rendering data. Try everything. */ pvt->palette_initialized = FALSE; + pvt->highlight_color_set = FALSE; memset(&pvt->palette, 0, sizeof(pvt->palette)); pvt->draw = _vte_draw_new(GTK_WIDGET(terminal)); /* The font description. */ pvt->fontdesc = NULL; + pvt->fontantialias = VTE_ANTI_ALIAS_USE_DEFAULT; pvt->connected_settings = NULL; gtk_widget_ensure_style(widget); vte_terminal_connect_xft_settings(terminal); - vte_terminal_set_font(terminal, NULL); + vte_terminal_set_font_full(terminal, NULL, VTE_ANTI_ALIAS_USE_DEFAULT); /* Input method support. */ pvt->im_context = NULL; pvt->im_preedit_active = FALSE; pvt->im_preedit = NULL; + pvt->im_preedit_attrs = NULL; pvt->im_preedit_cursor = 0; /* Bookkeeping data for adjustment-changed signals. */ @@ -10907,8 +11353,8 @@ pvt->accessible_emit = FALSE; #ifdef VTE_DEBUG - /* In debuggable mode, we always do this. */ - pvt->accessible = gtk_widget_get_accessible(GTK_WIDGET(terminal)); + /* In debuggable mode, we always used to do this. */ + /* gtk_widget_get_accessible(GTK_WIDGET(terminal)); */ #endif } @@ -11132,6 +11578,10 @@ g_free(terminal->pvt->im_preedit); terminal->pvt->im_preedit = NULL; } + if (terminal->pvt->im_preedit_attrs != NULL) { + pango_attr_list_unref(terminal->pvt->im_preedit_attrs); + terminal->pvt->im_preedit_attrs = NULL; + } terminal->pvt->im_preedit_cursor = 0; /* Unmap the widget if it hasn't been already. */ @@ -11214,6 +11664,7 @@ pango_font_description_free(terminal->pvt->fontdesc); terminal->pvt->fontdesc = NULL; } + terminal->pvt->fontantialias = VTE_ANTI_ALIAS_USE_DEFAULT; vte_terminal_disconnect_xft_settings(terminal); /* Free matching data. */ @@ -11238,7 +11689,8 @@ gdk_cursor_unref(regex->cursor); regex->cursor = NULL; } - regfree(®ex->reg); + _vte_regex_free(regex->reg); + regex->reg = NULL; regex->tag = 0; } g_array_free(terminal->pvt->match_regexes, TRUE); @@ -11497,7 +11949,8 @@ GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED); /* Actually load the font. */ - vte_terminal_set_font(terminal, terminal->pvt->fontdesc); + vte_terminal_set_font_full(terminal, terminal->pvt->fontdesc, + terminal->pvt->fontantialias); /* Allocate colors. */ for (i = 0; i < G_N_ELEMENTS(terminal->pvt->palette); i++) { @@ -11573,13 +12026,28 @@ static void vte_terminal_determine_colors(VteTerminal *terminal, const struct vte_charcell *cell, - gboolean reverse, int *fore, int *back) + gboolean reverse, + gboolean highlight, + gboolean cursor, + int *fore, int *back) { g_assert(fore != NULL); g_assert(back != NULL); /* Determine what the foreground and background colors for rendering - * text should be. */ + * text should be. If highlight is set and we have a highlight color, + * use that scheme. If cursor is set and we have a cursor color, use + * that scheme. If neither is set, and reverse is set, then use + * reverse colors, else use the defaults. This means that many callers + * who specify highlight or cursor should also specify reverse. */ + if (cursor && !highlight && terminal->pvt->cursor_color_set) { + *fore = cell ? cell->back : VTE_DEF_BG; + *back = VTE_CUR_BG; + } else + if (highlight && !cursor && terminal->pvt->highlight_color_set) { + *fore = cell ? cell->fore : VTE_DEF_FG; + *back = VTE_DEF_HL; + } else if (reverse ^ ((cell != NULL) && (cell->reverse))) { *fore = cell ? cell->back : VTE_DEF_BG; *back = cell ? cell->fore : VTE_DEF_FG; @@ -12682,6 +13150,247 @@ } } +/* Try to map a PangoColor to a palette entry and return its index. */ +static int +_vte_terminal_map_pango_color(VteTerminal *terminal, PangoColor *color) +{ + long distance[G_N_ELEMENTS(terminal->pvt->palette)]; + struct vte_palette_entry *entry; + int i, ret; + + /* Calculate a "distance" value. Could stand to be improved a bit. */ + for (i = 0; i < G_N_ELEMENTS(distance); i++) { + entry = &terminal->pvt->palette[i]; + distance[i] = 0; + distance[i] += ((entry->red >> 8) - (color->red >> 8)) * + ((entry->red >> 8) - (color->red >> 8)); + distance[i] += ((entry->blue >> 8) - (color->blue >> 8)) * + ((entry->blue >> 8) - (color->blue >> 8)); + distance[i] += ((entry->green >> 8) - (color->green >> 8)) * + ((entry->green >> 8) - (color->green >> 8)); + } + + /* Find the index of the minimum value. */ + ret = 0; + for (i = 1; i < G_N_ELEMENTS(distance); i++) { + if (distance[i] < distance[ret]) { + ret = i; + } + } + +#ifdef VTE_DEBUG + if (_vte_debug_on(VTE_DEBUG_UPDATES)) { + fprintf(stderr, "mapped PangoColor(%04x,%04x,%04x) to " + "palette entry (%04x,%04x,%04x)\n", + color->red, color->green, color->blue, + terminal->pvt->palette[ret].red, + terminal->pvt->palette[ret].green, + terminal->pvt->palette[ret].blue); + } +#endif + + return ret; +} + +/* FIXME: we don't have a way to tell GTK+ what the default text attributes + * should be, so for now at least it's assuming white-on-black is the norm and + * is using "black-on-white" to signify "inverse". Pick up on that state and + * fix things. Do this here, so that if we suddenly get red-on-black, we'll do + * the right thing. */ +static void +_vte_terminal_fudge_pango_colors(VteTerminal *terminal, GSList *attributes, + struct vte_charcell *cells, gssize n) +{ + gboolean saw_fg, saw_bg; + PangoAttribute *attr; + PangoAttrColor *color; + PangoColor fg, bg; + int i; + + saw_fg = saw_bg = FALSE; + + while (attributes != NULL) { + attr = attributes->data; + switch (attr->klass->type) { + case PANGO_ATTR_FOREGROUND: + saw_fg = TRUE; + color = (PangoAttrColor*) attr; + fg = color->color; + break; + case PANGO_ATTR_BACKGROUND: + saw_bg = TRUE; + color = (PangoAttrColor*) attr; + bg = color->color; + break; + default: + break; + } + attributes = g_slist_next(attributes); + } + + if (saw_fg && saw_bg && + (fg.red == 0xffff) && (fg.green == 0xffff) && (fg.blue == 0xffff) && + (bg.red == 0) && (bg.green == 0) && (bg.blue == 0)) { + for (i = 0; i < n; i++) { + cells[i].fore = terminal->pvt->screen->color_defaults.fore; + cells[i].back = terminal->pvt->screen->color_defaults.back; + cells[i].reverse = TRUE; + } + } +} + +/* Apply the attribute given in the PangoAttribute to the list of cells. */ +static void +_vte_terminal_apply_pango_attr(VteTerminal *terminal, PangoAttribute *attr, + struct vte_charcell *cells, gsize n_cells) +{ + int i, ival; + PangoAttrInt *attrint; + PangoAttrColor *attrcolor; + + switch (attr->klass->type) { + case PANGO_ATTR_FOREGROUND: + case PANGO_ATTR_BACKGROUND: + attrcolor = (PangoAttrColor*) attr; + ival = _vte_terminal_map_pango_color(terminal, + &attrcolor->color); + for (i = attr->start_index; + (ival >= 0) && (i < attr->end_index) && (i < n_cells); + i++) { + if (attr->klass->type == PANGO_ATTR_FOREGROUND) { + cells[i].fore = ival; + } + if (attr->klass->type == PANGO_ATTR_BACKGROUND) { + cells[i].back = ival; + } + } + break; + case PANGO_ATTR_STRIKETHROUGH: + attrint = (PangoAttrInt*) attr; + ival = attrint->value; + for (i = attr->start_index; + (i < attr->end_index) && (i < n_cells); + i++) { + cells[i].strikethrough = (ival != FALSE); + } + break; + case PANGO_ATTR_UNDERLINE: + attrint = (PangoAttrInt*) attr; + ival = attrint->value; + for (i = attr->start_index; + (i < attr->end_index) && (i < n_cells); + i++) { + cells[i].underline = (ival != PANGO_UNDERLINE_NONE); + } + break; + case PANGO_ATTR_WEIGHT: + attrint = (PangoAttrInt*) attr; + ival = attrint->value; + for (i = attr->start_index; + (i < attr->end_index) && (i < n_cells); + i++) { + cells[i].bold = (ival >= PANGO_WEIGHT_BOLD); + } + break; + default: + break; + } +} + +/* Convert a PangoAttrList and a location in that list to settings in a + * charcell structure. The cells array is assumed to contain enough items + * so that all ranges in the attribute list can be mapped into the array, which + * typically means that the cell array should have the same length as the + * string (byte-wise) which the attributes describe. */ +static void +_vte_terminal_pango_attribute_destroy(gpointer attr, gpointer data) +{ + pango_attribute_destroy(attr); +} +static void +_vte_terminal_translate_pango_cells(VteTerminal *terminal, PangoAttrList *attrs, + struct vte_charcell *cells, gsize n_cells) +{ + PangoAttribute *attr; + PangoAttrIterator *attriter; + GSList *list, *listiter; + int i; + + for (i = 0; i < n_cells; i++) { + cells[i] = terminal->pvt->screen->fill_defaults; + } + + attriter = pango_attr_list_get_iterator(attrs); + if (attriter != NULL) { + do { + list = pango_attr_iterator_get_attrs(attriter); + if (list != NULL) { + for (listiter = list; + listiter != NULL; + listiter = g_slist_next(listiter)) { + attr = listiter->data; + _vte_terminal_apply_pango_attr(terminal, + attr, + cells, + n_cells); + } + attr = list->data; + _vte_terminal_fudge_pango_colors(terminal, + list, + cells + + attr->start_index, + attr->end_index - + attr->start_index); + g_slist_foreach(list, + _vte_terminal_pango_attribute_destroy, + NULL); + g_slist_free(list); + } + } while (pango_attr_iterator_next(attriter) == TRUE); + pango_attr_iterator_destroy(attriter); + } +} + +/* Draw the listed items using the given attributes. Tricky because the + * attribute string is indexed by byte in the UTF-8 representation of the string + * of characters. Because we draw a character at a time, this is slower. */ +static void +vte_terminal_draw_cells_with_attributes(VteTerminal *terminal, + struct _vte_draw_text_request *items, + gssize n, + PangoAttrList *attrs, + gboolean draw_default_bg, + gint column_width, gint height) +{ + int i, j, cell_count; + struct vte_charcell *cells; + char scratch_buf[VTE_UTF8_BPC]; + int fore, back; + + for (i = 0, cell_count = 0; i < n; i++) { + cell_count += g_unichar_to_utf8(items[i].c, scratch_buf); + } + cells = g_malloc(cell_count * sizeof(struct vte_charcell)); + _vte_terminal_translate_pango_cells(terminal, attrs, cells, cell_count); + for (i = 0, j = 0; i < n; i++) { + vte_terminal_determine_colors(terminal, &cells[j], + FALSE, + FALSE, + FALSE, + &fore, &back); + vte_terminal_draw_cells(terminal, items + i, 1, + fore, + back, + draw_default_bg, + cells[j].bold, + cells[j].underline, + cells[j].strikethrough, + FALSE, FALSE, column_width, height); + j += g_unichar_to_utf8(items[i].c, scratch_buf); + } + g_free(cells); +} + static gboolean vte_terminal_get_blink_state(VteTerminal *terminal) { @@ -12736,7 +13445,7 @@ GArray *items; int i, j, fore, nfore, back, nback; gboolean underline, nunderline, bold, nbold, hilite, nhilite, reverse, - strikethrough, nstrikethrough, drawn; + selected, strikethrough, nstrikethrough, drawn; struct _vte_draw_text_request item; struct vte_charcell *cell; @@ -12760,9 +13469,12 @@ /* Get the character cell's contents. */ cell = vte_terminal_find_charcell(terminal, i, row); /* Find the colors for this cell. */ - reverse = vte_cell_is_selected(terminal, i, row, NULL) ^ - terminal->pvt->screen->reverse_mode; - vte_terminal_determine_colors(terminal, cell, reverse, + reverse = terminal->pvt->screen->reverse_mode; + selected = vte_cell_is_selected(terminal, i, row, NULL); + vte_terminal_determine_colors(terminal, cell, + reverse || selected, + selected, + FALSE, &fore, &back); underline = (cell != NULL) ? (cell->underline != 0) : FALSE; strikethrough = (cell != NULL) ? (cell->strikethrough != 0) : FALSE; @@ -12813,9 +13525,12 @@ /* Resolve attributes to colors where possible and * compare visual attributes to the first character * in this chunk. */ - reverse = vte_cell_is_selected(terminal, j, row, NULL) ^ - terminal->pvt->screen->reverse_mode; - vte_terminal_determine_colors(terminal, cell, reverse, + reverse = terminal->pvt->screen->reverse_mode; + selected = vte_cell_is_selected(terminal, j, row, NULL); + vte_terminal_determine_colors(terminal, cell, + reverse || selected, + selected, + FALSE, &nfore, &nback); if ((nfore != fore) || (nback != back)) { break; @@ -12904,10 +13619,11 @@ struct _vte_draw_text_request item, *items; int row, drow, col, row_stop, col_stop, columns; char *preedit; + int preedit_cursor; long width, height, ascent, descent, delta, cursor_width; int i, len, fore, back, x, y; GdkRectangle all_area; - gboolean blink; + gboolean blink, selected; #ifdef VTE_DEBUG if (_vte_debug_on(VTE_DEBUG_LIFECYCLE)) { @@ -13014,9 +13730,14 @@ cell->columns)); } if (GTK_WIDGET_HAS_FOCUS(GTK_WIDGET(terminal))) { + selected = vte_cell_is_selected(terminal, col, drow, + NULL); blink = vte_terminal_get_blink_state(terminal) ^ terminal->pvt->screen->reverse_mode; - vte_terminal_determine_colors(terminal, cell, blink, + vte_terminal_determine_colors(terminal, cell, + blink, + selected, + blink, &fore, &back); _vte_draw_clear(terminal->pvt->draw, col * width + VTE_PAD_WIDTH, @@ -13060,7 +13781,10 @@ } else { GdkColor color; /* Draw it as a hollow rectangle. */ - vte_terminal_determine_colors(terminal, cell, FALSE, + vte_terminal_determine_colors(terminal, cell, + FALSE, + FALSE, + FALSE, &fore, &back); _vte_draw_clear(terminal->pvt->draw, col * width + VTE_PAD_WIDTH, @@ -13095,6 +13819,7 @@ /* Find out how many columns the pre-edit string takes up. */ preedit = terminal->pvt->im_preedit; + preedit_cursor = -1; columns = vte_terminal_preedit_width(terminal, FALSE); len = vte_terminal_preedit_length(terminal, FALSE); @@ -13111,6 +13836,10 @@ (len + 1)); preedit = terminal->pvt->im_preedit; for (i = columns = 0; i < len; i++) { + if ((preedit - terminal->pvt->im_preedit) == + terminal->pvt->im_preedit_cursor) { + preedit_cursor = i; + } items[i].c = g_utf8_get_char(preedit); items[i].columns = _vte_iso2022_unichar_width(items[i].c); items[i].x = (col + columns) * width; @@ -13118,6 +13847,10 @@ columns += items[i].columns; preedit = g_utf8_next_char(preedit); } + if ((preedit - terminal->pvt->im_preedit) == + terminal->pvt->im_preedit_cursor) { + preedit_cursor = i; + } items[len].c = ' '; items[len].columns = 1; items[len].x = (col + columns) * width; @@ -13129,17 +13862,12 @@ height); fore = screen->defaults.fore; back = screen->defaults.back; - vte_terminal_draw_cells(terminal, - items, len + 1, - fore, back, TRUE, - FALSE, - FALSE, - FALSE, - FALSE, - TRUE, - width, height); - if ((terminal->pvt->im_preedit_cursor >= 0) && - (terminal->pvt->im_preedit_cursor < len)) { + vte_terminal_draw_cells_with_attributes(terminal, + items, len + 1, + terminal->pvt->im_preedit_attrs, + TRUE, + width, height); + if ((preedit_cursor >= 0) && (preedit_cursor < len)) { /* Cursored letter in reverse. */ vte_terminal_draw_cells(terminal, &items[terminal->pvt->im_preedit_cursor], 1, @@ -13151,7 +13879,7 @@ TRUE, width, height); } else - if (terminal->pvt->im_preedit_cursor == len) { + if (preedit_cursor == len) { /* Empty cursor at the end. */ vte_terminal_draw_cells(terminal, &items[len], 1, @@ -13315,6 +14043,9 @@ #endif bindtextdomain(PACKAGE, LOCALEDIR); +#ifdef HAVE_DECL_BIND_TEXTDOMAIN_CODESET + bind_textdomain_codeset(PACKAGE, "UTF-8"); +#endif gobject_class = G_OBJECT_CLASS(klass); widget_class = GTK_WIDGET_CLASS(klass); @@ -13338,12 +14069,44 @@ widget_class->get_accessible = vte_terminal_get_accessible; widget_class->show = vte_terminal_show; + /* Initialize default handlers. */ + klass->eof = NULL; + klass->child_exited = NULL; + klass->emulation_changed = NULL; + klass->encoding_changed = NULL; + klass->char_size_changed = NULL; + klass->window_title_changed = NULL; + klass->icon_title_changed = NULL; + klass->selection_changed = NULL; + klass->contents_changed = NULL; + klass->cursor_moved = NULL; + klass->status_line_changed = NULL; + klass->commit = NULL; + + klass->deiconify_window = NULL; + klass->iconify_window = NULL; + klass->raise_window = NULL; + klass->lower_window = NULL; + klass->refresh_window = NULL; + klass->restore_window = NULL; + klass->maximize_window = NULL; + klass->resize_window = NULL; + klass->move_window = NULL; + + klass->increase_font_size = NULL; + klass->decrease_font_size = NULL; + + klass->text_modified = NULL; + klass->text_inserted = NULL; + klass->text_deleted = NULL; + klass->text_scrolled = NULL; + /* Register some signals of our own. */ klass->eof_signal = g_signal_new("eof", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, eof), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13352,7 +14115,7 @@ g_signal_new("child-exited", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, child_exited), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13361,7 +14124,7 @@ g_signal_new("window-title-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, window_title_changed), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13370,7 +14133,7 @@ g_signal_new("icon-title-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, icon_title_changed), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13379,7 +14142,7 @@ g_signal_new("encoding-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, encoding_changed), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13388,7 +14151,7 @@ g_signal_new("commit", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, commit), NULL, NULL, _vte_marshal_VOID__STRING_UINT, @@ -13397,7 +14160,7 @@ g_signal_new("emulation-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, emulation_changed), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13406,7 +14169,7 @@ g_signal_new("char-size-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, char_size_changed), NULL, NULL, _vte_marshal_VOID__UINT_UINT, @@ -13415,7 +14178,7 @@ g_signal_new ("selection-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, selection_changed), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13424,7 +14187,7 @@ g_signal_new("contents-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, contents_changed), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13433,7 +14196,7 @@ g_signal_new("cursor-moved", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, cursor_moved), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13442,7 +14205,7 @@ g_signal_new("deiconify-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, deiconify_window), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13451,7 +14214,7 @@ g_signal_new("iconify-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, iconify_window), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13460,7 +14223,7 @@ g_signal_new("raise-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, raise_window), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13469,7 +14232,7 @@ g_signal_new("lower-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, lower_window), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13478,7 +14241,7 @@ g_signal_new("refresh-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, refresh_window), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13487,7 +14250,7 @@ g_signal_new("restore-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, restore_window), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13496,7 +14259,7 @@ g_signal_new("maximize-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, maximize_window), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13505,7 +14268,7 @@ g_signal_new("resize-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, resize_window), NULL, NULL, _vte_marshal_VOID__UINT_UINT, @@ -13514,7 +14277,7 @@ g_signal_new("move-window", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, move_window), NULL, NULL, _vte_marshal_VOID__UINT_UINT, @@ -13523,7 +14286,7 @@ g_signal_new("status-line-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, status_line_changed), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13532,7 +14295,7 @@ g_signal_new("increase-font-size", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, increase_font_size), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13541,7 +14304,7 @@ g_signal_new("decrease-font-size", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, decrease_font_size), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13550,7 +14313,7 @@ g_signal_new("text-modified", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, text_modified), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13559,7 +14322,7 @@ g_signal_new("text-inserted", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, text_inserted), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13568,7 +14331,7 @@ g_signal_new("text-deleted", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, text_deleted), NULL, NULL, _vte_marshal_VOID__VOID, @@ -13577,7 +14340,7 @@ g_signal_new("text-scrolled", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, - 0, + G_STRUCT_OFFSET(VteTerminalClass, text_scrolled), NULL, NULL, _vte_marshal_VOID__INT, @@ -13613,6 +14376,23 @@ } GtkType +vte_terminal_anti_alias_get_type(void) +{ + static GtkType terminal_anti_alias_type = 0; + static GEnumValue values[] = { + {VTE_ANTI_ALIAS_USE_DEFAULT, "VTE_ANTI_ALIAS_USE_DEFAULT", "use-default"}, + {VTE_ANTI_ALIAS_FORCE_ENABLE, "VTE_ANTI_ALIAS_FORCE_ENABLE", "force-enable"}, + {VTE_ANTI_ALIAS_FORCE_DISABLE, "VTE_ANTI_ALIAS_FORCE_DISABLE", "force-disable"}, + }; + if (terminal_anti_alias_type == 0) { + terminal_anti_alias_type = + g_enum_register_static("VteTerminalAntiAlias", + values); + } + return terminal_anti_alias_type; +} + +GtkType vte_terminal_get_type(void) { static GtkType terminal_type = 0; @@ -14331,7 +15111,7 @@ * characters can be specified by separating them with a hyphen. * * As a special case, if @spec is NULL or the empty string, the terminal will - * treat all graphic non-punctuation characters as word characters. + * treat all graphic non-punctuation non-space characters as word characters. */ void vte_terminal_set_word_chars(VteTerminal *terminal, const char *spec)