diff options
Diffstat (limited to 'src/vte.c')
-rw-r--r-- | src/vte.c | 7098 |
1 files changed, 2861 insertions, 4237 deletions
@@ -1,27 +1,28 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2001-2004,2009,2010 Red Hat, Inc. * Copyright © 2008, 2009, 2010 Christian Persch * - * This is free software; you can redistribute it and/or modify it under - * the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * SECTION: vte-terminal * @short_description: A terminal widget implementation * - * A VteTerminal is a terminal emulator implemented as a GTK2 widget. + * A VteTerminal is a terminal emulator implemented as a GTK3 widget. */ #include <config.h> @@ -30,7 +31,6 @@ #include "vte.h" #include "vte-private.h" -#include "vte-gtk-compat.h" #ifdef HAVE_WCHAR_H #include <wchar.h> @@ -56,18 +56,20 @@ #include "vteint.h" #include "vtepty.h" #include "vtepty-private.h" -#include "vteregex.h" #include "vtetc.h" #ifdef HAVE_LOCALE_H #include <locale.h> #endif -#if GTK_CHECK_VERSION (2, 90, 7) -#define GDK_KEY(symbol) GDK_KEY_##symbol -#else -#include <gdk/gdkkeysyms.h> -#define GDK_KEY(symbol) GDK_##symbol +#ifndef HAVE_ROUND +static inline double round(double x) { + if(x - floor(x) < 0.5) { + return floor(x); + } else { + return ceil(x); + } +} #endif #ifndef HAVE_WINT_T @@ -78,12 +80,8 @@ typedef gunichar wint_t; #define howmany(x, y) (((x) + ((y) - 1)) / (y)) #endif -#define STATIC_PARAMS (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB) - - static void vte_terminal_set_visibility (VteTerminal *terminal, GdkVisibilityState state); -static void vte_terminal_set_termcap(VteTerminal *terminal, const char *path, - gboolean reset); +static void vte_terminal_set_termcap(VteTerminal *terminal); static void vte_terminal_paste(VteTerminal *terminal, GdkAtom board); static void vte_terminal_real_copy_clipboard(VteTerminal *terminal); static void vte_terminal_real_paste_clipboard(VteTerminal *terminal); @@ -98,8 +96,7 @@ static void vte_terminal_match_hilite_hide(VteTerminal *terminal); static void vte_terminal_match_hilite_show(VteTerminal *terminal, long x, long y); static void vte_terminal_match_hilite_update(VteTerminal *terminal, long x, long y); static void vte_terminal_match_contents_clear(VteTerminal *terminal); -static gboolean vte_terminal_background_update(VteTerminal *data); -static void vte_terminal_queue_background_update(VteTerminal *terminal); +static void vte_terminal_background_update(VteTerminal *data); static void vte_terminal_process_incoming(VteTerminal *terminal); static void vte_terminal_emit_pending_signals(VteTerminal *terminal); static gboolean vte_cell_is_selected(VteTerminal *terminal, @@ -131,13 +128,16 @@ static void add_update_timeout (VteTerminal *terminal); static void remove_update_timeout (VteTerminal *terminal); static void reset_update_regions (VteTerminal *terminal); static void vte_terminal_set_cursor_blinks_internal(VteTerminal *terminal, gboolean blink); -static void vte_terminal_set_font_full_internal(VteTerminal *terminal, - const PangoFontDescription *font_desc, - VteTerminalAntiAlias antialias); static void _vte_check_cursor_blink(VteTerminal *terminal); static gboolean process_timeout (gpointer data); static gboolean update_timeout (gpointer data); +static cairo_region_t *vte_cairo_get_clip_region (cairo_t *cr); +static void vte_terminal_determine_colors_internal(VteTerminal *terminal, + const VteCellAttr *attr, + gboolean selected, + gboolean cursor, + guint *pfore, guint *pback); enum { COPY_CLIPBOARD, @@ -148,23 +148,18 @@ static guint signals[LAST_SIGNAL]; enum { PROP_0, -#if GTK_CHECK_VERSION (2, 91, 2) PROP_HADJUSTMENT, PROP_VADJUSTMENT, PROP_HSCROLL_POLICY, PROP_VSCROLL_POLICY, -#endif PROP_ALLOW_BOLD, PROP_AUDIBLE_BELL, - PROP_BACKGROUND_IMAGE_FILE, - PROP_BACKGROUND_IMAGE_PIXBUF, - PROP_BACKGROUND_OPACITY, - PROP_BACKGROUND_SATURATION, - PROP_BACKGROUND_TINT_COLOR, - PROP_BACKGROUND_TRANSPARENT, PROP_BACKSPACE_BINDING, + PROP_CJK_AMBIGUOUS_WIDTH, PROP_CURSOR_BLINK_MODE, PROP_CURSOR_SHAPE, + PROP_CURRENT_DIRECTORY_URI, + PROP_CURRENT_FILE_URI, PROP_DELETE_BINDING, PROP_EMULATION, PROP_ENCODING, @@ -172,14 +167,13 @@ enum { PROP_ICON_TITLE, PROP_MOUSE_POINTER_AUTOHIDE, PROP_PTY, - PROP_PTY_OBJECT, - PROP_SCROLL_BACKGROUND, + PROP_REWRAP_ON_RESIZE, PROP_SCROLLBACK_LINES, PROP_SCROLL_ON_KEYSTROKE, PROP_SCROLL_ON_OUTPUT, PROP_WINDOW_TITLE, - PROP_WORD_CHARS, - PROP_VISIBLE_BELL + PROP_VISIBLE_BELL, + PROP_FONT_SCALE }; /* these static variables are guarded by the GDK mutex */ @@ -190,7 +184,7 @@ static gboolean in_update_timeout; static GList *active_terminals; static GTimer *process_timer; -static const GtkBorder default_inner_border = { 1, 1, 1, 1 }; +static const GtkBorder default_padding = { 1, 1, 1, 1 }; /* process incoming data without copying */ static struct _vte_incoming_chunk *free_chunks; @@ -282,7 +276,6 @@ _vte_incoming_chunks_reverse(struct _vte_incoming_chunk *chunk) return prev; } -#if GTK_CHECK_VERSION (2, 99, 0) #ifdef VTE_DEBUG G_DEFINE_TYPE_WITH_CODE(VteTerminal, vte_terminal, GTK_TYPE_WIDGET, g_type_add_class_private (g_define_type_id, sizeof (VteTerminalClassPrivate)); @@ -295,16 +288,6 @@ G_DEFINE_TYPE_WITH_CODE(VteTerminal, vte_terminal, GTK_TYPE_WIDGET, g_type_add_class_private (g_define_type_id, sizeof (VteTerminalClassPrivate)); G_IMPLEMENT_INTERFACE(GTK_TYPE_SCROLLABLE, NULL)) #endif -#else -#ifdef VTE_DEBUG -G_DEFINE_TYPE_WITH_CODE(VteTerminal, vte_terminal, GTK_TYPE_WIDGET, - if (_vte_debug_on(VTE_DEBUG_LIFECYCLE)) { - g_printerr("vte_terminal_get_type()\n"); - }) -#else -G_DEFINE_TYPE(VteTerminal, vte_terminal, GTK_TYPE_WIDGET) -#endif -#endif /* GTK 3.0 */ /* Indexes in the "palette" color array for the dim colors. * Only the first %VTE_LEGACY_COLOR_SET_SIZE colors have dim versions. */ @@ -330,11 +313,12 @@ _vte_terminal_ring_insert (VteTerminal *terminal, glong position, gboolean fill) VteRing *ring = terminal->pvt->screen->row_data; while (G_UNLIKELY (_vte_ring_next (ring) < position)) { row = _vte_ring_append (ring); - _vte_row_data_fill (row, &terminal->pvt->screen->fill_defaults, terminal->column_count); + if (terminal->pvt->screen->fill_defaults.attr.back != VTE_DEFAULT_BG) + _vte_row_data_fill (row, &terminal->pvt->screen->fill_defaults, terminal->pvt->column_count); } row = _vte_ring_insert (ring, position); - if (fill) - _vte_row_data_fill (row, &terminal->pvt->screen->fill_defaults, terminal->column_count); + if (fill && terminal->pvt->screen->fill_defaults.attr.back != VTE_DEFAULT_BG) + _vte_row_data_fill (row, &terminal->pvt->screen->fill_defaults, terminal->pvt->column_count); return row; } @@ -369,15 +353,17 @@ _vte_invalidate_cells(VteTerminal *terminal, glong column_start, gint column_count, glong row_start, gint row_count) { - VteRegionRectangle rect; + cairo_rectangle_int_t rect; glong i; + if (G_UNLIKELY (!gtk_widget_get_realized(&terminal->widget))) + return; + if (!column_count || !row_count) { return; } - if (G_UNLIKELY (! gtk_widget_is_drawable (&terminal->widget) - || terminal->pvt->invalidated_all)) { + if (terminal->pvt->invalidated_all) { return; } @@ -394,25 +380,25 @@ _vte_invalidate_cells(VteTerminal *terminal, row_start -= terminal->pvt->screen->scroll_delta; /* Ensure the start of region is on screen */ - if (column_start > terminal->column_count || - row_start > terminal->row_count) { + if (column_start > terminal->pvt->column_count || + row_start > terminal->pvt->row_count) { return; } /* Clamp the start values to reasonable numbers. */ i = row_start + row_count; row_start = MAX (0, row_start); - row_count = CLAMP (i - row_start, 0, terminal->row_count); + row_count = CLAMP (i - row_start, 0, terminal->pvt->row_count); i = column_start + column_count; column_start = MAX (0, column_start); - column_count = CLAMP (i - column_start, 0 , terminal->column_count); + column_count = CLAMP (i - column_start, 0 , terminal->pvt->column_count); if (!column_count || !row_count) { return; } - if (column_count == terminal->column_count && - row_count == terminal->row_count) { + if (column_count == terminal->pvt->column_count && + row_count == terminal->pvt->row_count) { _vte_invalidate_all (terminal); return; } @@ -421,23 +407,23 @@ _vte_invalidate_cells(VteTerminal *terminal, * by multiplying by the size of a character cell. * Always include the extra pixel border and overlap pixel. */ - rect.x = column_start * terminal->char_width - 1; + rect.x = column_start * terminal->pvt->char_width - 1; if (column_start != 0) { - rect.x += terminal->pvt->inner_border.left; + rect.x += terminal->pvt->padding.left; } - rect.width = (column_start + column_count) * terminal->char_width + 3 + terminal->pvt->inner_border.left; - if (column_start + column_count == terminal->column_count) { - rect.width += terminal->pvt->inner_border.right; + rect.width = (column_start + column_count) * terminal->pvt->char_width + 3 + terminal->pvt->padding.left; + if (column_start + column_count == terminal->pvt->column_count) { + rect.width += terminal->pvt->padding.right; } rect.width -= rect.x; - rect.y = row_start * terminal->char_height - 1; + rect.y = row_start * terminal->pvt->char_height - 1; if (row_start != 0) { - rect.y += terminal->pvt->inner_border.top; + rect.y += terminal->pvt->padding.top; } - rect.height = (row_start + row_count) * terminal->char_height + 2 + terminal->pvt->inner_border.top; - if (row_start + row_count == terminal->row_count) { - rect.height += terminal->pvt->inner_border.bottom; + rect.height = (row_start + row_count) * terminal->pvt->char_height + 2 + terminal->pvt->padding.top; + if (row_start + row_count == terminal->pvt->row_count) { + rect.height += terminal->pvt->padding.bottom; } rect.height -= rect.y; @@ -448,7 +434,7 @@ _vte_invalidate_cells(VteTerminal *terminal, if (terminal->pvt->active != NULL) { terminal->pvt->update_regions = g_slist_prepend ( terminal->pvt->update_regions, - gdk_region_rectangle (&rect)); + cairo_region_create_rectangle (&rect)); /* Wait a bit before doing any invalidation, just in * case updates are coming in really soon. */ add_update_timeout (terminal); @@ -472,10 +458,10 @@ _vte_invalidate_region (VteTerminal *terminal, } else { _vte_invalidate_cells(terminal, scolumn, - terminal->column_count - scolumn, + terminal->pvt->column_count - scolumn, srow, 1); _vte_invalidate_cells(terminal, - 0, terminal->column_count, + 0, terminal->pvt->column_count, srow + 1, erow - srow - 1); _vte_invalidate_cells(terminal, 0, ecolumn + 1, @@ -488,14 +474,14 @@ _vte_invalidate_region (VteTerminal *terminal, void _vte_invalidate_all(VteTerminal *terminal) { - VteRegionRectangle rect; + cairo_rectangle_int_t rect; GtkAllocation allocation; g_assert(VTE_IS_TERMINAL(terminal)); - if (! gtk_widget_is_drawable (&terminal->widget)) { - return; - } + if (G_UNLIKELY (!gtk_widget_get_realized(&terminal->widget))) + return; + if (terminal->pvt->invalidated_all) { return; } @@ -514,7 +500,7 @@ _vte_invalidate_all(VteTerminal *terminal) if (terminal->pvt->active != NULL) { terminal->pvt->update_regions = g_slist_prepend (NULL, - gdk_region_rectangle (&rect)); + cairo_region_create_rectangle (&rect)); /* Wait a bit before doing any invalidation, just in * case updates are coming in really soon. */ add_update_timeout (terminal); @@ -534,14 +520,14 @@ _vte_terminal_scroll_region (VteTerminal *terminal, return; } - if (terminal->pvt->scroll_background || count >= terminal->row_count) { + if (count >= terminal->pvt->row_count) { /* We have to repaint the entire window. */ _vte_invalidate_all(terminal); } else { /* We have to repaint the area which is to be * scrolled. */ _vte_invalidate_cells(terminal, - 0, terminal->column_count, + 0, terminal->pvt->column_count, row, count); } } @@ -615,7 +601,7 @@ find_end_column (VteTerminal *terminal, glong col, glong row) columns = cell->attr.columns - 1; } } - return MIN(col + columns, terminal->column_count); + return MIN(col + columns, terminal->pvt->column_count); } @@ -673,9 +659,12 @@ _vte_invalidate_cell(VteTerminal *terminal, glong col, glong row) { const VteRowData *row_data; int columns; + guint style; + + if (G_UNLIKELY (!gtk_widget_get_realized(&terminal->widget))) + return; - if (G_UNLIKELY (! gtk_widget_is_drawable (&terminal->widget) - || terminal->pvt->invalidated_all)) { + if (terminal->pvt->invalidated_all) { return; } @@ -689,12 +678,12 @@ _vte_invalidate_cell(VteTerminal *terminal, glong col, glong row) cell = _vte_row_data_get (row_data, --col); } columns = cell->attr.columns; + style = _vte_draw_get_style(cell->attr.bold, cell->attr.italic); if (cell->c != 0 && _vte_draw_get_char_width ( terminal->pvt->draw, - cell->c, - columns, cell->attr.bold) > - terminal->char_width * columns) { + cell->c, columns, style) > + terminal->pvt->char_width * columns) { columns++; } } @@ -717,6 +706,10 @@ _vte_invalidate_cursor_once(VteTerminal *terminal, gboolean periodic) gssize preedit_width; glong column, row; gint columns; + guint style; + + if (G_UNLIKELY(!gtk_widget_get_realized(&terminal->widget))) + return; if (terminal->pvt->invalidated_all) { return; @@ -728,7 +721,7 @@ _vte_invalidate_cursor_once(VteTerminal *terminal, gboolean periodic) } } - if (terminal->pvt->cursor_visible && gtk_widget_is_drawable (&terminal->widget)) { + if (terminal->pvt->cursor_visible) { preedit_width = vte_terminal_preedit_width(terminal, FALSE); screen = terminal->pvt->screen; @@ -739,12 +732,13 @@ _vte_invalidate_cursor_once(VteTerminal *terminal, gboolean periodic) cell = vte_terminal_find_charcell(terminal, column, row); if (cell != NULL) { columns = cell->attr.columns; + style = _vte_draw_get_style(cell->attr.bold, cell->attr.italic); if (cell->c != 0 && _vte_draw_get_char_width ( terminal->pvt->draw, cell->c, - columns, cell->attr.bold) > - terminal->char_width * columns) { + columns, style) > + terminal->pvt->char_width * columns) { columns++; } } @@ -847,11 +841,12 @@ vte_terminal_emit_encoding_changed(VteTerminal *terminal) /* Emit a "child-exited" signal. */ static void -vte_terminal_emit_child_exited(VteTerminal *terminal) +vte_terminal_emit_child_exited(VteTerminal *terminal, + int status) { _vte_debug_print(VTE_DEBUG_SIGNALS, "Emitting `child-exited'.\n"); - g_signal_emit_by_name(terminal, "child-exited"); + g_signal_emit_by_name(terminal, "child-exited", status); } /* Emit a "contents_changed" signal. */ @@ -905,9 +900,15 @@ vte_terminal_emit_eof(VteTerminal *terminal) { _vte_debug_print(VTE_DEBUG_SIGNALS, "Emitting `eof'.\n"); - GDK_THREADS_ENTER (); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_enter (); + G_GNUC_END_IGNORE_DEPRECATIONS; + g_signal_emit_by_name(terminal, "eof"); - GDK_THREADS_LEAVE (); + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_leave (); + G_GNUC_END_IGNORE_DEPRECATIONS; return FALSE; } @@ -1142,7 +1143,7 @@ regex_match_clear_cursor (struct vte_match_regex *regex) switch (regex->cursor_mode) { case VTE_REGEX_CURSOR_GDKCURSOR: if (regex->cursor.cursor != NULL) { - gdk_cursor_unref(regex->cursor.cursor); + g_object_unref(regex->cursor.cursor); regex->cursor.cursor = NULL; } break; @@ -1163,13 +1164,8 @@ regex_match_clear (struct vte_match_regex *regex) { regex_match_clear_cursor(regex); - if (regex->mode == VTE_REGEX_GREGEX) { - g_regex_unref(regex->regex.gregex.regex); - regex->regex.gregex.regex = NULL; - } else if (regex->mode == VTE_REGEX_VTE) { - _vte_regex_free(regex->regex.reg); - regex->regex.reg = NULL; - } + g_regex_unref(regex->regex); + regex->regex = NULL; regex->tag = -1; } @@ -1185,7 +1181,7 @@ vte_terminal_set_cursor_from_regex_match(VteTerminal *terminal, struct vte_match switch (regex->cursor_mode) { case VTE_REGEX_CURSOR_GDKCURSOR: if (regex->cursor.cursor != NULL) { - cursor = gdk_cursor_ref(regex->cursor.cursor); + cursor = g_object_ref(regex->cursor.cursor); } break; case VTE_REGEX_CURSOR_GDKCURSORTYPE: @@ -1202,18 +1198,20 @@ vte_terminal_set_cursor_from_regex_match(VteTerminal *terminal, struct vte_match gdk_window_set_cursor (gtk_widget_get_window (&terminal->widget), cursor); if (cursor) - gdk_cursor_unref(cursor); + g_object_unref(cursor); } /** - * vte_terminal_match_clear_all: + * vte_terminal_match_remove_all: * @terminal: a #VteTerminal * * Clears the list of regular expressions the terminal uses to highlight text * when the user moves the mouse cursor. + * + * Since: 0.30 */ void -vte_terminal_match_clear_all(VteTerminal *terminal) +vte_terminal_match_remove_all(VteTerminal *terminal) { struct vte_match_regex *regex; guint i; @@ -1272,65 +1270,6 @@ vte_terminal_cursor_new(VteTerminal *terminal, GdkCursorType cursor_type) } /** - * vte_terminal_match_add: - * @terminal: a #VteTerminal - * @match: a regular expression - * - * Adds a regular expression to the list of matching expressions. When the - * user moves the mouse cursor over a section of displayed text which matches - * this expression, the text will be highlighted. - * - * Returns: an integer associated with this expression - * - * Deprecated: 0.17.1: Use vte_terminal_match_add_gregex() instead - */ -int -vte_terminal_match_add(VteTerminal *terminal, const char *match) -{ - struct vte_match_regex new_regex, *regex; - guint ret; - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - g_return_val_if_fail(terminal->pvt->match_regex_mode != VTE_REGEX_GREGEX, -1); - g_return_val_if_fail(match != NULL, -1); - g_return_val_if_fail(strlen(match) > 0, -1); - - terminal->pvt->match_regex_mode = VTE_REGEX_VTE; - - memset(&new_regex, 0, sizeof(new_regex)); - new_regex.mode = VTE_REGEX_VTE; - new_regex.regex.reg = _vte_regex_compile(match); - if (new_regex.regex.reg == NULL) { - g_warning(_("Error compiling regular expression \"%s\"."), - match); - return -1; - } - - /* Search for a hole. */ - for (ret = 0; ret < terminal->pvt->match_regexes->len; ret++) { - regex = &g_array_index(terminal->pvt->match_regexes, - struct vte_match_regex, - ret); - if (regex->tag == -1) { - break; - } - } - /* Set the tag to the insertion point. */ - new_regex.tag = ret; - new_regex.cursor_mode = VTE_REGEX_CURSOR_GDKCURSORTYPE; - new_regex.cursor.cursor_type = VTE_DEFAULT_CURSOR; - if (ret < terminal->pvt->match_regexes->len) { - /* Overwrite. */ - g_array_index(terminal->pvt->match_regexes, - struct vte_match_regex, - ret) = new_regex; - } else { - /* Append. */ - g_array_append_val(terminal->pvt->match_regexes, new_regex); - } - return new_regex.tag; -} - -/** * vte_terminal_match_add_gregex: * @terminal: a #VteTerminal * @regex: a #GRegex @@ -1352,11 +1291,9 @@ vte_terminal_match_add_gregex(VteTerminal *terminal, GRegex *regex, GRegexMatchF guint ret, len; g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - g_return_val_if_fail(terminal->pvt->match_regex_mode != VTE_REGEX_VTE, -1); g_return_val_if_fail(regex != NULL, -1); pvt = terminal->pvt; - pvt->match_regex_mode = VTE_REGEX_GREGEX; /* Search for a hole. */ len = pvt->match_regexes->len; @@ -1370,9 +1307,8 @@ vte_terminal_match_add_gregex(VteTerminal *terminal, GRegex *regex, GRegexMatchF } /* Set the tag to the insertion point. */ - new_regex_match.mode = VTE_REGEX_GREGEX; - new_regex_match.regex.gregex.regex = g_regex_ref(regex); - new_regex_match.regex.gregex.flags = flags; + new_regex_match.regex = g_regex_ref(regex); + new_regex_match.match_flags = flags; new_regex_match.tag = ret; new_regex_match.cursor_mode = VTE_REGEX_CURSOR_GDKCURSORTYPE; new_regex_match.cursor.cursor_type = VTE_DEFAULT_CURSOR; @@ -1413,7 +1349,7 @@ vte_terminal_match_set_cursor(VteTerminal *terminal, int tag, GdkCursor *cursor) tag); regex_match_clear_cursor(regex); regex->cursor_mode = VTE_REGEX_CURSOR_GDKCURSOR; - regex->cursor.cursor = cursor ? gdk_cursor_ref(cursor) : NULL; + regex->cursor.cursor = cursor ? g_object_ref(cursor) : NULL; vte_terminal_match_hilite_clear(terminal); } @@ -1478,231 +1414,6 @@ vte_terminal_match_set_cursor_name(VteTerminal *terminal, * it does, return the string, and store the match tag in the optional tag * argument. */ static char * -vte_terminal_match_check_internal_vte(VteTerminal *terminal, - long column, glong row, - int *tag, int *start, int *end) -{ - struct _vte_regex_match matches[256]; - guint i, j; - gint k; - gint start_blank, end_blank; - int ret, offset; - struct vte_match_regex *regex = NULL; - struct _VteCharAttributes *attr = NULL; - gssize sattr, eattr; - gchar *line, eol; - - _vte_debug_print(VTE_DEBUG_EVENTS, - "Checking for match at (%ld,%ld).\n", row, column); - *tag = -1; - if (start != NULL) { - *start = 0; - } - if (end != NULL) { - *end = 0; - } - /* Map the pointer position to a portion of the string. */ - eattr = terminal->pvt->match_attributes->len; - for (offset = eattr; offset--; ) { - attr = &g_array_index(terminal->pvt->match_attributes, - struct _VteCharAttributes, - offset); - if (row < attr->row) { - eattr = offset; - } - if (row == attr->row && - column == attr->column && - terminal->pvt->match_contents[offset] != ' ') { - break; - } - } - - _VTE_DEBUG_IF(VTE_DEBUG_EVENTS) { - if (offset < 0) - g_printerr("Cursor is not on a character.\n"); - else - g_printerr("Cursor is on character '%c' at %d.\n", - g_utf8_get_char (terminal->pvt->match_contents + offset), - offset); - } - - /* If the pointer isn't on a matchable character, bug out. */ - if (offset < 0) { - return NULL; - } - - /* If the pointer is on a newline, bug out. */ - if ((g_ascii_isspace(terminal->pvt->match_contents[offset])) || - (terminal->pvt->match_contents[offset] == '\0')) { - _vte_debug_print(VTE_DEBUG_EVENTS, - "Cursor is on whitespace.\n"); - return NULL; - } - - /* Snip off any final newlines. */ - while (terminal->pvt->match_contents[eattr] == '\n' || - terminal->pvt->match_contents[eattr] == '\0') { - eattr--; - } - /* and scan forwards to find the end of this line */ - while (!(terminal->pvt->match_contents[eattr] == '\n' || - terminal->pvt->match_contents[eattr] == '\0')) { - eattr++; - } - - /* find the start of row */ - if (row == 0) { - sattr = 0; - } else { - for (sattr = offset; sattr > 0; sattr--) { - attr = &g_array_index(terminal->pvt->match_attributes, - struct _VteCharAttributes, - sattr); - if (row > attr->row) { - break; - } - } - } - /* Scan backwards to find the start of this line */ - while (sattr > 0 && - ! (terminal->pvt->match_contents[sattr] == '\n' || - terminal->pvt->match_contents[sattr] == '\0')) { - sattr--; - } - /* and skip any initial newlines. */ - while (terminal->pvt->match_contents[sattr] == '\n' || - terminal->pvt->match_contents[sattr] == '\0') { - sattr++; - } - if (eattr <= sattr) { /* blank line */ - return NULL; - } - if (eattr <= offset || sattr > offset) { - /* nothing to match on this line */ - return NULL; - } - offset -= sattr; - eattr -= sattr; - - /* temporarily shorten the contents to this row */ - line = terminal->pvt->match_contents + sattr; - eol = line[eattr]; - line[eattr] = '\0'; - - start_blank = 0; - end_blank = eattr; - - /* Now iterate over each regex we need to match against. */ - for (i = 0; i < terminal->pvt->match_regexes->len; i++) { - regex = &g_array_index(terminal->pvt->match_regexes, - struct vte_match_regex, - i); - /* Skip holes. */ - if (regex->tag < 0) { - continue; - } - /* We'll only match the first item in the buffer which - * matches, so we'll have to skip each match until we - * stop getting matches. */ - k = 0; - ret = _vte_regex_exec(regex->regex.reg, - line + k, - G_N_ELEMENTS(matches), - matches); - while (ret == 0) { - gint ko = offset - k; - gint sblank=G_MININT, eblank=G_MAXINT; - for (j = 0; - j < G_N_ELEMENTS(matches) && - matches[j].rm_so != -1; - j++) { - /* The offsets should be "sane". */ - g_assert(matches[j].rm_so + k < eattr); - g_assert(matches[j].rm_eo + k <= eattr); - _VTE_DEBUG_IF(VTE_DEBUG_MISC) { - gchar *match; - struct _VteCharAttributes *_sattr, *_eattr; - match = g_strndup(line + matches[j].rm_so + k, - matches[j].rm_eo - matches[j].rm_so); - _sattr = &g_array_index(terminal->pvt->match_attributes, - struct _VteCharAttributes, - matches[j].rm_so + k); - _eattr = &g_array_index(terminal->pvt->match_attributes, - struct _VteCharAttributes, - matches[j].rm_eo + k - 1); - g_printerr("Match %u `%s' from %d(%ld,%ld) to %d(%ld,%ld) (%d).\n", - j, match, - matches[j].rm_so + k, - _sattr->column, - _sattr->row, - matches[j].rm_eo + k - 1, - _eattr->column, - _eattr->row, - offset); - g_free(match); - - } - /* If the pointer is in this substring, - * then we're done. */ - if (ko >= matches[j].rm_so && - ko < matches[j].rm_eo) { - gchar *result; - if (tag != NULL) { - *tag = regex->tag; - } - if (start != NULL) { - *start = sattr + k + matches[j].rm_so; - } - if (end != NULL) { - *end = sattr + k + matches[j].rm_eo - 1; - } - vte_terminal_set_cursor_from_regex_match(terminal, regex); - result = g_strndup(line + k + matches[j].rm_so, - matches[j].rm_eo - matches[j].rm_so); - line[eattr] = eol; - return result; - } - if (ko > matches[j].rm_eo && - matches[j].rm_eo > sblank) { - sblank = matches[j].rm_eo; - } - if (ko < matches[j].rm_so && - matches[j].rm_so < eblank) { - eblank = matches[j].rm_so; - } - } - if (k + sblank > start_blank) { - start_blank = k + sblank; - } - if (k + eblank < end_blank) { - end_blank = k + eblank; - } - /* Skip past the beginning of this match to - * look for more. */ - k += matches[0].rm_so + 1; - if (k > offset) { - break; - } - ret = _vte_regex_exec(regex->regex.reg, - line + k, - G_N_ELEMENTS(matches), - matches); - } - } - line[eattr] = eol; - if (start != NULL) { - *start = sattr + start_blank; - } - if (end != NULL) { - *end = sattr + end_blank; - } - return NULL; -} - -/* Check if a given cell on the screen contains part of a matched string. If - * it does, return the string, and store the match tag in the optional tag - * argument. */ -static char * vte_terminal_match_check_internal_gregex(VteTerminal *terminal, long column, glong row, int *tag, int *start, int *end) @@ -1718,7 +1429,9 @@ vte_terminal_match_check_internal_gregex(VteTerminal *terminal, _vte_debug_print(VTE_DEBUG_EVENTS, "Checking for gregex match at (%ld,%ld).\n", row, column); - *tag = -1; + if (tag != NULL) { + *tag = -1; + } if (start != NULL) { *start = 0; } @@ -1828,9 +1541,9 @@ vte_terminal_match_check_internal_gregex(VteTerminal *terminal, /* We'll only match the first item in the buffer which * matches, so we'll have to skip each match until we * stop getting matches. */ - if (!g_regex_match_full(regex->regex.gregex.regex, + if (!g_regex_match_full(regex->regex, line, -1, 0, - regex->regex.gregex.flags, + regex->match_flags, &match_info, NULL)) { g_match_info_free(match_info); @@ -1929,11 +1642,7 @@ vte_terminal_match_check_internal(VteTerminal *terminal, vte_terminal_match_contents_refresh(terminal); } - if (terminal->pvt->match_regex_mode == VTE_REGEX_GREGEX) - return vte_terminal_match_check_internal_gregex(terminal, column, row, tag, start, end); - if (terminal->pvt->match_regex_mode == VTE_REGEX_VTE) - return vte_terminal_match_check_internal_vte(terminal, column, row, tag, start, end); - return NULL; + return vte_terminal_match_check_internal_gregex(terminal, column, row, tag, start, end); } static gboolean @@ -2016,15 +1725,15 @@ vte_terminal_emit_adjustment_changed(VteTerminal *terminal) glong v; gdouble current; - g_object_freeze_notify (G_OBJECT (terminal->adjustment)); + g_object_freeze_notify (G_OBJECT (terminal->pvt->vadjustment)); v = _vte_ring_delta (screen->row_data); - current = gtk_adjustment_get_lower(terminal->adjustment); + current = gtk_adjustment_get_lower(terminal->pvt->vadjustment); if (current != v) { _vte_debug_print(VTE_DEBUG_ADJ, "Changing lower bound from %.0f to %ld\n", current, v); - gtk_adjustment_set_lower(terminal->adjustment, v); + gtk_adjustment_set_lower(terminal->pvt->vadjustment, v); changed = TRUE; } @@ -2032,16 +1741,16 @@ vte_terminal_emit_adjustment_changed(VteTerminal *terminal) * one to the cursor offset because it's zero-based.) */ v = MAX(_vte_ring_next(screen->row_data), screen->cursor_current.row + 1); - current = gtk_adjustment_get_upper(terminal->adjustment); + current = gtk_adjustment_get_upper(terminal->pvt->vadjustment); if (current != v) { _vte_debug_print(VTE_DEBUG_ADJ, "Changing upper bound from %.0f to %ld\n", current, v); - gtk_adjustment_set_upper(terminal->adjustment, v); + gtk_adjustment_set_upper(terminal->pvt->vadjustment, v); changed = TRUE; } - g_object_thaw_notify (G_OBJECT (terminal->adjustment)); + g_object_thaw_notify (G_OBJECT (terminal->pvt->vadjustment)); if (changed) _vte_debug_print(VTE_DEBUG_SIGNALS, @@ -2053,7 +1762,7 @@ vte_terminal_emit_adjustment_changed(VteTerminal *terminal) _vte_debug_print(VTE_DEBUG_SIGNALS, "Emitting adjustment_value_changed.\n"); terminal->pvt->adjustment_value_changed_pending = FALSE; - v = round (gtk_adjustment_get_value(terminal->adjustment)); + v = round (gtk_adjustment_get_value(terminal->pvt->vadjustment)); if (v != terminal->pvt->screen->scroll_delta) { /* this little dance is so that the scroll_delta is * updated immediately, but we still handled scrolling @@ -2062,7 +1771,7 @@ vte_terminal_emit_adjustment_changed(VteTerminal *terminal) */ delta = terminal->pvt->screen->scroll_delta; terminal->pvt->screen->scroll_delta = v; - gtk_adjustment_set_value(terminal->adjustment, delta); + gtk_adjustment_set_value(terminal->pvt->vadjustment, delta); } } } @@ -2090,10 +1799,10 @@ vte_terminal_queue_adjustment_value_changed_clamped(VteTerminal *terminal, glong { gdouble lower, upper; - lower = gtk_adjustment_get_lower(terminal->adjustment); - upper = gtk_adjustment_get_upper(terminal->adjustment); + lower = gtk_adjustment_get_lower(terminal->pvt->vadjustment); + upper = gtk_adjustment_get_upper(terminal->pvt->vadjustment); - v = CLAMP(v, lower, MAX (lower, upper - terminal->row_count)); + v = CLAMP(v, lower, MAX (lower, upper - terminal->pvt->row_count)); vte_terminal_queue_adjustment_value_changed (terminal, v); } @@ -2139,44 +1848,44 @@ _vte_terminal_adjust_adjustments_full (VteTerminal *terminal) _vte_terminal_adjust_adjustments(terminal); - g_object_freeze_notify(G_OBJECT(terminal->adjustment)); + g_object_freeze_notify(G_OBJECT(terminal->pvt->vadjustment)); /* The step increment should always be one. */ - v = gtk_adjustment_get_step_increment(terminal->adjustment); + v = gtk_adjustment_get_step_increment(terminal->pvt->vadjustment); if (v != 1) { _vte_debug_print(VTE_DEBUG_ADJ, "Changing step increment from %.0lf to %ld\n", - v, terminal->row_count); - gtk_adjustment_set_step_increment(terminal->adjustment, 1); + v, terminal->pvt->row_count); + gtk_adjustment_set_step_increment(terminal->pvt->vadjustment, 1); changed = TRUE; } /* Set the number of rows the user sees to the number of rows the * user sees. */ - v = gtk_adjustment_get_page_size(terminal->adjustment); - if (v != terminal->row_count) { + v = gtk_adjustment_get_page_size(terminal->pvt->vadjustment); + if (v != terminal->pvt->row_count) { _vte_debug_print(VTE_DEBUG_ADJ, "Changing page size from %.0f to %ld\n", - v, terminal->row_count); - gtk_adjustment_set_page_size(terminal->adjustment, - terminal->row_count); + v, terminal->pvt->row_count); + gtk_adjustment_set_page_size(terminal->pvt->vadjustment, + terminal->pvt->row_count); changed = TRUE; } /* Clicking in the empty area should scroll one screen, so set the * page size to the number of visible rows. */ - v = gtk_adjustment_get_page_increment(terminal->adjustment); - if (v != terminal->row_count) { + v = gtk_adjustment_get_page_increment(terminal->pvt->vadjustment); + if (v != terminal->pvt->row_count) { _vte_debug_print(VTE_DEBUG_ADJ, "Changing page increment from " "%.0f to %ld\n", - v, terminal->row_count); - gtk_adjustment_set_page_increment(terminal->adjustment, - terminal->row_count); + v, terminal->pvt->row_count); + gtk_adjustment_set_page_increment(terminal->pvt->vadjustment, + terminal->pvt->row_count); changed = TRUE; } - g_object_thaw_notify(G_OBJECT(terminal->adjustment)); + g_object_thaw_notify(G_OBJECT(terminal->pvt->vadjustment)); if (changed) _vte_debug_print(VTE_DEBUG_SIGNALS, @@ -2200,7 +1909,7 @@ vte_terminal_scroll_lines(VteTerminal *terminal, gint lines) static void vte_terminal_scroll_pages(VteTerminal *terminal, gint pages) { - vte_terminal_scroll_lines(terminal, pages * terminal->row_count); + vte_terminal_scroll_lines(terminal, pages * terminal->pvt->row_count); } /* Scroll so that the scroll delta is the minimum value. */ @@ -2288,11 +1997,11 @@ vte_terminal_set_encoding(VteTerminal *terminal, const char *codeset) terminal->pvt->encoding = g_intern_string(codeset); /* Convert any buffered output bytes. */ - if ((_vte_buffer_length(terminal->pvt->outgoing) > 0) && + if ((_vte_byte_array_length(terminal->pvt->outgoing) > 0) && (old_codeset != NULL)) { /* Convert back to UTF-8. */ obuf1 = g_convert((gchar *)terminal->pvt->outgoing->data, - _vte_buffer_length(terminal->pvt->outgoing), + _vte_byte_array_length(terminal->pvt->outgoing), "UTF-8", old_codeset, NULL, @@ -2308,8 +2017,8 @@ vte_terminal_set_encoding(VteTerminal *terminal, const char *codeset) &bytes_written, NULL); if (obuf2 != NULL) { - _vte_buffer_clear(terminal->pvt->outgoing); - _vte_buffer_append(terminal->pvt->outgoing, + _vte_byte_array_clear(terminal->pvt->outgoing); + _vte_byte_array_append(terminal->pvt->outgoing, obuf2, bytes_written); g_free(obuf2); } @@ -2345,6 +2054,49 @@ vte_terminal_get_encoding(VteTerminal *terminal) return terminal->pvt->encoding; } +/** + * vte_terminal_set_cjk_ambiguous_width: + * @terminal: a #VteTerminal + * @width: either 1 (narrow) or 2 (wide) + * + * This setting controls whether ambiguous-width characters are narrow or wide + * when using the UTF-8 encoding (vte_terminal_set_encoding()). In all other encodings, + * the width of ambiguous-width characters is fixed. + * + * This setting only takes effect the next time the terminal is reset, either + * via escape sequence or with vte_terminal_reset(). + * + * Since: 0.38 + */ +void +vte_terminal_set_cjk_ambiguous_width(VteTerminal *terminal, int width) +{ + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(width == 1 || width == 2); + + terminal->pvt->iso2022_utf8_ambiguous_width = width; + if (terminal->pvt->pty == NULL) + _vte_iso2022_state_set_utf8_ambiguous_width(terminal->pvt->iso2022, width); +} + +/** + * vte_terminal_get_cjk_ambiguous_width: + * @terminal: a #VteTerminal + * + * Returns whether ambiguous-width characters are narrow or wide when using + * the UTF-8 encoding (vte_terminal_set_encoding()). + * + * Returns: 1 if ambiguous-width characters are narrow, or 2 if they are wide + * + * Since: 0.38 + */ +int +vte_terminal_get_cjk_ambiguous_width(VteTerminal *terminal) +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), 1); + return terminal->pvt->iso2022_utf8_ambiguous_width; +} + static inline VteRowData * vte_terminal_insert_rows (VteTerminal *terminal, guint cnt) { @@ -2418,9 +2170,9 @@ _vte_terminal_update_insert_delta(VteTerminal *terminal) * the buffer (even if it's empty). This usually causes the * top row to become a history-only row. */ delta = screen->insert_delta; - delta = MIN(delta, rows - terminal->row_count); + delta = MIN(delta, rows - terminal->pvt->row_count); delta = MAX(delta, - screen->cursor_current.row - (terminal->row_count - 1)); + screen->cursor_current.row - (terminal->pvt->row_count - 1)); delta = MAX(delta, _vte_ring_delta(screen->row_data)); /* Adjust the insert delta and scroll if needed. */ @@ -2472,7 +2224,7 @@ _vte_terminal_set_pointer_visible(VteTerminal *terminal, gboolean visible) * * Creates a new terminal widget. * - * Returns: (transfer full) (type Vte.Terminal): a new #VteTerminal object + * Returns: (transfer none) (type Vte.Terminal): a new #VteTerminal object */ GtkWidget * vte_terminal_new(void) @@ -2480,30 +2232,56 @@ vte_terminal_new(void) return g_object_new(VTE_TYPE_TERMINAL, NULL); } +/* Get the actually used color from the palette. */ +PangoColor * +_vte_terminal_get_color(const VteTerminal *terminal, int entry) +{ + VtePaletteColor *palette_color = &terminal->pvt->palette[entry]; + guint source; + for (source = 0; source < G_N_ELEMENTS(palette_color->sources); source++) + if (palette_color->sources[source].is_set) + return &palette_color->sources[source].color; + return NULL; +} + /* Set up a palette entry with a more-or-less match for the requested color. */ -static void -vte_terminal_set_color_internal(VteTerminal *terminal, int entry, - const GdkColor *proposed) +void +_vte_terminal_set_color_internal(VteTerminal *terminal, + int entry, + int source, + const PangoColor *proposed) { - PangoColor *color; + VtePaletteColor *palette_color = &terminal->pvt->palette[entry]; - color = &terminal->pvt->palette[entry]; + /* Save the requested color. */ + if (proposed != NULL) { + _vte_debug_print(VTE_DEBUG_MISC, + "Set %s color[%d] to (%04x,%04x,%04x).\n", + source == VTE_COLOR_SOURCE_ESCAPE ? "escape" : "API", + entry, proposed->red, proposed->green, proposed->blue); + + if (palette_color->sources[source].is_set && + palette_color->sources[source].color.red == proposed->red && + palette_color->sources[source].color.green == proposed->green && + palette_color->sources[source].color.blue == proposed->blue) { + return; + } + palette_color->sources[source].is_set = TRUE; + palette_color->sources[source].color.red = proposed->red; + palette_color->sources[source].color.green = proposed->green; + palette_color->sources[source].color.blue = proposed->blue; + } else { + _vte_debug_print(VTE_DEBUG_MISC, + "Reset %s color[%d].\n", + source == VTE_COLOR_SOURCE_ESCAPE ? "escape" : "API", + entry); - if (color->red == proposed->red && - color->green == proposed->green && - color->blue == proposed->blue) { - return; + if (!palette_color->sources[source].is_set) { + return; + } + palette_color->sources[source].is_set = FALSE; } - _vte_debug_print(VTE_DEBUG_MISC, - "Set color[%d] to (%04x,%04x,%04x).\n", entry, - proposed->red, proposed->green, proposed->blue); - - /* Save the requested color. */ - color->red = proposed->red; - color->green = proposed->green; - color->blue = proposed->blue; - /* If we're not realized yet, there's nothing else to do. */ if (! gtk_widget_get_realized (&terminal->widget)) { return; @@ -2511,12 +2289,12 @@ vte_terminal_set_color_internal(VteTerminal *terminal, int entry, /* If we're setting the background color, set the background color * on the widget as well. */ - if (entry == VTE_DEF_BG) { - vte_terminal_queue_background_update(terminal); + if (entry == VTE_DEFAULT_BG) { + vte_terminal_background_update(terminal); } /* and redraw */ - if (entry == VTE_CUR_BG) + if (entry == VTE_CURSOR_BG) _vte_invalidate_cursor_once(terminal, FALSE); else _vte_invalidate_all (terminal); @@ -2526,7 +2304,7 @@ static void vte_terminal_generate_bold(const PangoColor *foreground, const PangoColor *background, double factor, - GdkColor *bold) + PangoColor *bold /* (out) (callee allocates) */) { double fy, fcb, fcr, by, bcb, bcr, r, g, b; g_assert(foreground != NULL); @@ -2560,7 +2338,6 @@ vte_terminal_generate_bold(const PangoColor *foreground, "Calculated bold (%d, %d, %d) = (%lf,%lf,%lf)", foreground->red, foreground->green, foreground->blue, r, g, b); - bold->pixel = 0; bold->red = CLAMP(r, 0, 0xffff); bold->green = CLAMP(g, 0, 0xffff); bold->blue = CLAMP(b, 0, 0xffff); @@ -2569,154 +2346,179 @@ vte_terminal_generate_bold(const PangoColor *foreground, bold->red, bold->green, bold->blue); } -/** - * vte_terminal_set_color_bold: +/* + * _vte_terminal_set_color_bold: * @terminal: a #VteTerminal * @bold: the new bold color * * Sets the color used to draw bold text in the default foreground color. */ -void -vte_terminal_set_color_bold(VteTerminal *terminal, const GdkColor *bold) +static void +_vte_terminal_set_color_bold(VteTerminal *terminal, + const PangoColor *bold) { - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(bold != NULL); - _vte_debug_print(VTE_DEBUG_MISC, "Set bold color to (%04x,%04x,%04x).\n", bold->red, bold->green, bold->blue); - vte_terminal_set_color_internal(terminal, VTE_BOLD_FG, bold); + _vte_terminal_set_color_internal(terminal, VTE_BOLD_FG, VTE_COLOR_SOURCE_API, bold); } -/** - * vte_terminal_set_color_dim: +/* + * _vte_terminal_set_color_dim: * @terminal: a #VteTerminal * @dim: the new dim color * * Sets the color used to draw dim text in the default foreground color. */ -void -vte_terminal_set_color_dim(VteTerminal *terminal, const GdkColor *dim) +static void +_vte_terminal_set_color_dim(VteTerminal *terminal, + const PangoColor *dim) { - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(dim != NULL); - _vte_debug_print(VTE_DEBUG_MISC, "Set dim color to (%04x,%04x,%04x).\n", dim->red, dim->green, dim->blue); - vte_terminal_set_color_internal(terminal, VTE_DIM_FG, dim); + _vte_terminal_set_color_internal(terminal, VTE_DIM_FG, VTE_COLOR_SOURCE_API, dim); } -/** - * vte_terminal_set_color_foreground: +/* + * _vte_terminal_set_color_foreground: * @terminal: a #VteTerminal * @foreground: the new foreground color * * Sets the foreground color used to draw normal text */ -void -vte_terminal_set_color_foreground(VteTerminal *terminal, - const GdkColor *foreground) +static void +_vte_terminal_set_color_foreground(VteTerminal *terminal, + const PangoColor *foreground) { - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(foreground != NULL); - _vte_debug_print(VTE_DEBUG_MISC, "Set foreground color to (%04x,%04x,%04x).\n", foreground->red, foreground->green, foreground->blue); - vte_terminal_set_color_internal(terminal, VTE_DEF_FG, foreground); + _vte_terminal_set_color_internal(terminal, VTE_DEFAULT_FG, VTE_COLOR_SOURCE_API, foreground); } -/** - * vte_terminal_set_color_background: +/* + * _vte_terminal_set_color_background: * @terminal: a #VteTerminal * @background: the new background color * * Sets the background color for text which does not have a specific background - * color assigned. Only has effect when no background image is set and when - * the terminal is not transparent. + * color assigned. Only has effect when no background image is set. */ -void -vte_terminal_set_color_background(VteTerminal *terminal, - const GdkColor *background) +static void +_vte_terminal_set_color_background(VteTerminal *terminal, + const PangoColor *background) { - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(background != NULL); - _vte_debug_print(VTE_DEBUG_MISC, "Set background color to (%04x,%04x,%04x).\n", background->red, background->green, background->blue); - vte_terminal_set_color_internal(terminal, VTE_DEF_BG, background); + _vte_terminal_set_color_internal(terminal, VTE_DEFAULT_BG, VTE_COLOR_SOURCE_API, background); } -/** - * vte_terminal_set_color_cursor: +/* + * _vte_terminal_set_background_alpha: + * @terminal: a #VteTerminal + * @alpha: an alpha value from 0.0 to 0.1 + */ +static void +_vte_terminal_set_background_alpha(VteTerminal *terminal, + gdouble alpha) +{ + VteTerminalPrivate *pvt = terminal->pvt; + + if (alpha == pvt->background_alpha) + return; + + _vte_debug_print(VTE_DEBUG_MISC, + "Setting background alpha to %.3f\n", alpha); + + pvt->background_alpha = alpha; + + vte_terminal_background_update(terminal); +} + +/* + * _vte_terminal_set_color_cursor: * @terminal: a #VteTerminal * @cursor_background: (allow-none): the new color to use for the text cursor, or %NULL * * 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) +static void +_vte_terminal_set_color_cursor(VteTerminal *terminal, + const PangoColor *cursor_background) { - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - if (cursor_background != NULL) { _vte_debug_print(VTE_DEBUG_MISC, "Set cursor color to (%04x,%04x,%04x).\n", cursor_background->red, cursor_background->green, cursor_background->blue); - vte_terminal_set_color_internal(terminal, VTE_CUR_BG, - cursor_background); - terminal->pvt->cursor_color_set = TRUE; } else { _vte_debug_print(VTE_DEBUG_MISC, - "Cleared cursor color.\n"); - terminal->pvt->cursor_color_set = FALSE; + "Reset cursor color.\n"); } + _vte_terminal_set_color_internal(terminal, VTE_CURSOR_BG, VTE_COLOR_SOURCE_API, cursor_background); } -/** - * vte_terminal_set_color_highlight: +/* + * _vte_terminal_set_color_highlight: * @terminal: a #VteTerminal * @highlight_background: (allow-none): the new color to use for highlighted text, or %NULL * * Sets the background color for text which is highlighted. If %NULL, + * it is unset. If neither highlight background nor highlight foreground are set, * 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) +static void +_vte_terminal_set_color_highlight(VteTerminal *terminal, + const PangoColor *highlight_background) { - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - if (highlight_background != NULL) { _vte_debug_print(VTE_DEBUG_MISC, - "Set highlight color to (%04x,%04x,%04x).\n", + "Set highlight background color to (%04x,%04x,%04x).\n", highlight_background->red, highlight_background->green, highlight_background->blue); - vte_terminal_set_color_internal(terminal, VTE_DEF_HL, - highlight_background); - terminal->pvt->highlight_color_set = TRUE; } else { _vte_debug_print(VTE_DEBUG_MISC, - "Cleared highlight color.\n"); - terminal->pvt->highlight_color_set = FALSE; + "Reset highlight background color.\n"); } + _vte_terminal_set_color_internal(terminal, VTE_HIGHLIGHT_BG, VTE_COLOR_SOURCE_API, highlight_background); } -/** - * vte_terminal_set_colors: +/* + * _vte_terminal_set_color_highlight_foreground: + * @terminal: a #VteTerminal + * @highlight_foreground: (allow-none): the new color to use for highlighted text, or %NULL + * + * Sets the foreground color for text which is highlighted. If %NULL, + * it is unset. If neither highlight background nor highlight foreground are set, + * highlighted text (which is usually highlighted because it is selected) will + * be drawn with foreground and background colors reversed. + */ +static void +_vte_terminal_set_color_highlight_foreground(VteTerminal *terminal, + const PangoColor *highlight_foreground) +{ + if (highlight_foreground != NULL) { + _vte_debug_print(VTE_DEBUG_MISC, + "Set highlight foreground color to (%04x,%04x,%04x).\n", + highlight_foreground->red, + highlight_foreground->green, + highlight_foreground->blue); + } else { + _vte_debug_print(VTE_DEBUG_MISC, + "Reset highlight foreground color.\n"); + } + _vte_terminal_set_color_internal(terminal, VTE_HIGHLIGHT_FG, VTE_COLOR_SOURCE_API, highlight_foreground); +} + +/* + * _vte_terminal_set_colors: * @terminal: a #VteTerminal * @foreground: (allow-none): the new foreground color, or %NULL * @background: (allow-none): the new background color, or %NULL @@ -2728,7 +2530,7 @@ vte_terminal_set_color_highlight(VteTerminal *terminal, * color, an eight color palette, bold versions of the eight color palette, * and a dim version of the the eight color palette. * - * @palette_size must be either 0, 8, 16, or 24, or between 25 and 255 inclusive. + * @palette_size must be either 0, 8, 16, or 24, or between 25 and 256 inclusive. * If @foreground is %NULL and * @palette_size is greater than 0, the new foreground color is taken from * @palette[7]. If @background is %NULL and @palette_size is greater than 0, @@ -2737,27 +2539,19 @@ vte_terminal_set_color_highlight(VteTerminal *terminal, * 8-color palettes are extrapolated from the new background color and the items * in @palette. */ -void -vte_terminal_set_colors(VteTerminal *terminal, - const GdkColor *foreground, - const GdkColor *background, - const GdkColor *palette, - glong palette_size) +static void +_vte_terminal_set_colors(VteTerminal *terminal, + const PangoColor *foreground, + const PangoColor *background, + const PangoColor *palette, + gsize palette_size) { - guint i; - GdkColor color; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - - g_return_if_fail(palette_size >= 0); - g_return_if_fail((palette_size == 0) || - (palette_size == 8) || - (palette_size == 16) || - (palette_size == 24) || - (palette_size > 24 && palette_size < 256)); + gsize i; + PangoColor color; + gboolean unset = FALSE; _vte_debug_print(VTE_DEBUG_MISC, - "Set color palette [%ld elements].\n", + "Set color palette [%" G_GSIZE_FORMAT " elements].\n", palette_size); /* Accept NULL as the default foreground and background colors if we @@ -2774,6 +2568,7 @@ vte_terminal_set_colors(VteTerminal *terminal, /* Initialize each item in the palette if we got any entries to work * with. */ for (i=0; i < G_N_ELEMENTS(terminal->pvt->palette); i++) { + unset = FALSE; if (i < 16) { color.blue = (i & 4) ? 0xc000 : 0; color.green = (i & 2) ? 0xc000 : 0; @@ -2798,7 +2593,7 @@ vte_terminal_set_colors(VteTerminal *terminal, color.red = color.green = color.blue = shade | shade << 8; } else switch (i) { - case VTE_DEF_BG: + case VTE_DEFAULT_BG: if (background != NULL) { color = *background; } else { @@ -2807,7 +2602,7 @@ vte_terminal_set_colors(VteTerminal *terminal, color.green = 0; } break; - case VTE_DEF_FG: + case VTE_DEFAULT_FG: if (foreground != NULL) { color = *foreground; } else { @@ -2817,47 +2612,46 @@ vte_terminal_set_colors(VteTerminal *terminal, } break; case VTE_BOLD_FG: - vte_terminal_generate_bold(&terminal->pvt->palette[VTE_DEF_FG], - &terminal->pvt->palette[VTE_DEF_BG], + vte_terminal_generate_bold(_vte_terminal_get_color(terminal, VTE_DEFAULT_FG), + _vte_terminal_get_color(terminal, VTE_DEFAULT_BG), 1.8, &color); break; case VTE_DIM_FG: - vte_terminal_generate_bold(&terminal->pvt->palette[VTE_DEF_FG], - &terminal->pvt->palette[VTE_DEF_BG], + vte_terminal_generate_bold(_vte_terminal_get_color(terminal, VTE_DEFAULT_FG), + _vte_terminal_get_color(terminal, VTE_DEFAULT_BG), 0.5, &color); break; - case VTE_DEF_HL: - color.red = 0xc000; - color.blue = 0xc000; - color.green = 0xc000; + case VTE_HIGHLIGHT_BG: + unset = TRUE; break; - case VTE_CUR_BG: - color.red = 0x0000; - color.blue = 0x0000; - color.green = 0x0000; + case VTE_HIGHLIGHT_FG: + unset = TRUE; + break; + case VTE_CURSOR_BG: + unset = TRUE; break; } /* Override from the supplied palette if there is one. */ - if ((glong) i < palette_size) { + if (i < palette_size) { color = palette[i]; } /* Set up the color entry. */ - vte_terminal_set_color_internal(terminal, i, &color); + _vte_terminal_set_color_internal(terminal, i, VTE_COLOR_SOURCE_API, unset ? NULL : &color); + if (!terminal->pvt->palette_initialized) + terminal->pvt->palette[i].sources[VTE_COLOR_SOURCE_ESCAPE].is_set = FALSE; } /* Track that we had a color palette set. */ terminal->pvt->palette_initialized = TRUE; } -#if GTK_CHECK_VERSION (2, 99, 0) - -static GdkColor * -gdk_color_from_rgba (GdkColor *color, - const GdkRGBA *rgba) +static PangoColor * +_pango_color_from_rgba (PangoColor *color, + const GdkRGBA *rgba) { if (rgba == NULL) return NULL; @@ -2865,7 +2659,6 @@ gdk_color_from_rgba (GdkColor *color, color->red = rgba->red * 65535.; color->green = rgba->green * 65535.; color->blue = rgba->blue * 65535.; - color->pixel = 0; return color; } @@ -2882,21 +2675,23 @@ void vte_terminal_set_color_bold_rgba(VteTerminal *terminal, const GdkRGBA *bold) { - GdkColor color; + PangoColor color; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); if (bold == NULL) { - vte_terminal_generate_bold(&terminal->pvt->palette[VTE_DEF_FG], - &terminal->pvt->palette[VTE_DEF_BG], + vte_terminal_generate_bold(_vte_terminal_get_color(terminal, VTE_DEFAULT_FG), + _vte_terminal_get_color(terminal, VTE_DEFAULT_BG), 1.8, &color); } else { - gdk_color_from_rgba(&color, bold); + _pango_color_from_rgba(&color, bold); } - vte_terminal_set_color_bold(terminal, &color); + _vte_terminal_set_color_bold(terminal, &color); } /** @@ -2913,21 +2708,23 @@ void vte_terminal_set_color_dim_rgba(VteTerminal *terminal, const GdkRGBA *dim) { - GdkColor color; + PangoColor color; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); if (dim == NULL) { - vte_terminal_generate_bold(&terminal->pvt->palette[VTE_DEF_FG], - &terminal->pvt->palette[VTE_DEF_BG], + vte_terminal_generate_bold(_vte_terminal_get_color(terminal, VTE_DEFAULT_FG), + _vte_terminal_get_color(terminal, VTE_DEFAULT_BG), 0.5, &color); } else { - gdk_color_from_rgba(&color, dim); + _pango_color_from_rgba(&color, dim); } - vte_terminal_set_color_dim(terminal, &color); + _vte_terminal_set_color_dim(terminal, &color); } /** @@ -2943,10 +2740,13 @@ void vte_terminal_set_color_foreground_rgba(VteTerminal *terminal, const GdkRGBA *foreground) { - GdkColor color; + PangoColor color; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(foreground != NULL); - vte_terminal_set_color_foreground(terminal, - gdk_color_from_rgba(&color, foreground)); + _vte_terminal_set_color_foreground(terminal, + _pango_color_from_rgba(&color, foreground)); } /** @@ -2964,10 +2764,14 @@ void vte_terminal_set_color_background_rgba(VteTerminal *terminal, const GdkRGBA *background) { - GdkColor color; + PangoColor color; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(background != NULL); - vte_terminal_set_color_background(terminal, - gdk_color_from_rgba (&color, background)); + _vte_terminal_set_color_background(terminal, + _pango_color_from_rgba (&color, background)); + _vte_terminal_set_background_alpha(terminal, background->alpha); } /** @@ -2985,10 +2789,13 @@ void vte_terminal_set_color_cursor_rgba(VteTerminal *terminal, const GdkRGBA *cursor_background) { - GdkColor color; + PangoColor color; - vte_terminal_set_color_cursor(terminal, - gdk_color_from_rgba(&color, cursor_background)); + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(cursor_background != NULL); + + _vte_terminal_set_color_cursor(terminal, + _pango_color_from_rgba(&color, cursor_background)); } /** @@ -2997,6 +2804,7 @@ vte_terminal_set_color_cursor_rgba(VteTerminal *terminal, * @highlight_background: (allow-none): the new color to use for highlighted text, or %NULL * * Sets the background color for text which is highlighted. If %NULL, + * it is unset. If neither highlight background nor highlight foreground are set, * highlighted text (which is usually highlighted because it is selected) will * be drawn with foreground and background colors reversed. * @@ -3006,10 +2814,38 @@ void vte_terminal_set_color_highlight_rgba(VteTerminal *terminal, const GdkRGBA *highlight_background) { - GdkColor color; + PangoColor color; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(highlight_background != NULL); + + _vte_terminal_set_color_highlight(terminal, + _pango_color_from_rgba(&color, highlight_background)); +} + +/** + * vte_terminal_set_color_highlight_foreground_rgba: + * @terminal: a #VteTerminal + * @highlight_foreground: (allow-none): the new color to use for highlighted text, or %NULL + * + * Sets the foreground color for text which is highlighted. If %NULL, + * it is unset. If neither highlight background nor highlight foreground are set, + * highlighted text (which is usually highlighted because it is selected) will + * be drawn with foreground and background colors reversed. + * + * Since: 0.36 + */ +void +vte_terminal_set_color_highlight_foreground_rgba(VteTerminal *terminal, + const GdkRGBA *highlight_foreground) +{ + PangoColor color; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(highlight_foreground != NULL); - vte_terminal_set_color_highlight(terminal, - gdk_color_from_rgba(&color, highlight_background)); + _vte_terminal_set_color_highlight_foreground(terminal, + _pango_color_from_rgba(&color, highlight_foreground)); } /** @@ -3025,7 +2861,7 @@ vte_terminal_set_color_highlight_rgba(VteTerminal *terminal, * color, an eight color palette, bold versions of the eight color palette, * and a dim version of the the eight color palette. * - * @palette_size must be either 0, 8, 16, or 24, or between 25 and 255 inclusive. + * @palette_size must be either 0, 8, 16, or 24, or between 25 and 256 inclusive. * If @foreground is %NULL and * @palette_size is greater than 0, the new foreground color is taken from * @palette[7]. If @background is %NULL and @palette_size is greater than 0, @@ -3043,48 +2879,28 @@ vte_terminal_set_colors_rgba(VteTerminal *terminal, const GdkRGBA *palette, gsize palette_size) { - GdkColor fg, bg, *pal; + PangoColor fg, bg, *pal; gsize i; - pal = g_new (GdkColor, palette_size); + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail((palette_size == 0) || + (palette_size == 8) || + (palette_size == 16) || + (palette_size == 24) || + (palette_size > 24 && palette_size <= 256)); + + pal = g_new (PangoColor, palette_size); for (i = 0; i < palette_size; ++i) - gdk_color_from_rgba(&pal[i], &palette[i]); + _pango_color_from_rgba(&pal[i], &palette[i]); - vte_terminal_set_colors(terminal, - gdk_color_from_rgba(&fg, foreground), - gdk_color_from_rgba(&bg, background), - pal, palette_size); + _vte_terminal_set_colors(terminal, + _pango_color_from_rgba(&fg, foreground), + _pango_color_from_rgba(&bg, background), + pal, palette_size); g_free (pal); } -#endif /* GTK 3.0 */ - -/** - * vte_terminal_set_opacity: - * @terminal: a #VteTerminal - * @opacity: the new opacity - * - * Sets the opacity of the terminal background, were 0 means completely - * transparent and 65535 means completely opaque. - */ -void -vte_terminal_set_opacity(VteTerminal *terminal, guint16 opacity) -{ - VteTerminalPrivate *pvt; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - - pvt = terminal->pvt; - - if (opacity == pvt->bg_opacity) - return; - - pvt->bg_opacity = opacity; - - g_object_notify(G_OBJECT(terminal), "background-opacity"); -} - /** * vte_terminal_set_default_colors: * @terminal: a #VteTerminal @@ -3095,7 +2911,7 @@ void vte_terminal_set_default_colors(VteTerminal *terminal) { g_return_if_fail(VTE_IS_TERMINAL(terminal)); - vte_terminal_set_colors(terminal, NULL, NULL, NULL, 0); + _vte_terminal_set_colors(terminal, NULL, NULL, NULL, 0); } @@ -3144,23 +2960,15 @@ _vte_terminal_cursor_down (VteTerminal *terminal) end = screen->insert_delta + screen->scrolling_region.end; } else { start = screen->insert_delta; - end = start + terminal->row_count - 1; + end = start + terminal->pvt->row_count - 1; } if (screen->cursor_current.row == end) { - /* Match xterm and fill to the end of row when scrolling. */ - if (screen->fill_defaults.attr.back != VTE_DEF_BG) { - VteRowData *rowdata; - rowdata = _vte_terminal_ensure_row (terminal); - _vte_row_data_fill (rowdata, &screen->fill_defaults, terminal->column_count); - } - if (screen->scrolling_restricted) { if (start == screen->insert_delta) { /* Scroll this line into the scrollback * buffer by inserting a line at the next * line and scrolling the area up. */ screen->insert_delta++; - screen->scroll_delta++; screen->cursor_current.row++; /* update start and end, as they are relative * to insert_delta. */ @@ -3183,7 +2991,7 @@ _vte_terminal_cursor_down (VteTerminal *terminal) _vte_terminal_scroll_region(terminal, start, end - start + 1, -1); _vte_invalidate_cells(terminal, - 0, terminal->column_count, + 0, terminal->pvt->column_count, end - 2, 2); } } else { @@ -3193,10 +3001,10 @@ _vte_terminal_cursor_down (VteTerminal *terminal) } /* Match xterm and fill the new row when scrolling. */ - if (screen->fill_defaults.attr.back != VTE_DEF_BG) { + if (screen->fill_defaults.attr.back != VTE_DEFAULT_BG) { VteRowData *rowdata; rowdata = _vte_terminal_ensure_row (terminal); - _vte_row_data_fill (rowdata, &screen->fill_defaults, terminal->column_count); + _vte_row_data_fill (rowdata, &screen->fill_defaults, terminal->pvt->column_count); } } else { /* Otherwise, just move the cursor down. */ @@ -3248,7 +3056,7 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c, /* If we're autowrapping here, do it. */ col = screen->cursor_current.col; - if (G_UNLIKELY (columns && col + columns > terminal->column_count)) { + if (G_UNLIKELY (columns && col + columns > terminal->pvt->column_count)) { if (terminal->pvt->flags.am) { _vte_debug_print(VTE_DEBUG_ADJ, "Autowrapping before character\n"); @@ -3262,7 +3070,7 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c, } else { /* Don't wrap, stay at the rightmost column. */ col = screen->cursor_current.col = - terminal->column_count - columns; + terminal->pvt->column_count - columns; } line_wrapped = TRUE; } @@ -3270,8 +3078,8 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c, _vte_debug_print(VTE_DEBUG_PARSE, "Inserting %ld '%c' (%d/%d) (%ld+%d, %ld), delta = %ld; ", (long)c, c < 256 ? c : ' ', - screen->defaults.attr.fore, - screen->defaults.attr.back, + screen->color_defaults.attr.fore, + screen->color_defaults.attr.back, col, columns, (long)screen->cursor_current.row, (long)screen->insert_delta); @@ -3376,6 +3184,8 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c, } attr = screen->defaults.attr; + attr.fore = screen->color_defaults.attr.fore; + attr.back = screen->color_defaults.attr.back; attr.columns = columns; if (G_UNLIKELY (c == '_' && terminal->pvt->flags.ul)) { @@ -3407,20 +3217,20 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c, pcell->attr = attr; col++; } - _vte_row_data_shrink (row, terminal->column_count); + _vte_row_data_shrink (row, terminal->pvt->column_count); /* Signal that this part of the window needs drawing. */ if (G_UNLIKELY (invalidate_now)) { _vte_invalidate_cells(terminal, col - columns, - insert ? terminal->column_count : columns, + insert ? terminal->pvt->column_count : columns, screen->cursor_current.row, 1); } /* If we're autowrapping *here*, do it. */ screen->cursor_current.col = col; - if (G_UNLIKELY (col >= terminal->column_count)) { + if (G_UNLIKELY (col >= terminal->pvt->column_count)) { if (terminal->pvt->flags.am && !terminal->pvt->flags.xn) { /* Wrap. */ screen->cursor_current.col = 0; @@ -3441,11 +3251,10 @@ not_inserted: return line_wrapped; } -/* Catch a VteReaper child-exited signal, and if it matches the one we're - * looking for, emit one of our own. */ static void -vte_terminal_catch_child_exited(VteReaper *reaper, int pid, int status, - VteTerminal *terminal) +vte_terminal_child_watch_cb(GPid pid, + int status, + VteTerminal *terminal) { if (pid == terminal->pvt->pty_pid) { GObject *object = G_OBJECT(terminal); @@ -3466,22 +3275,15 @@ vte_terminal_catch_child_exited(VteReaper *reaper, int pid, int status, } #endif } - /* Disconnect from the reaper. */ - if (terminal->pvt->pty_reaper != NULL) { - g_signal_handlers_disconnect_by_func(terminal->pvt->pty_reaper, - vte_terminal_catch_child_exited, - terminal); - g_object_unref(terminal->pvt->pty_reaper); - terminal->pvt->pty_reaper = NULL; - } + + terminal->pvt->child_watch_source = 0; terminal->pvt->pty_pid = -1; /* Close out the PTY. */ - vte_terminal_set_pty_object(terminal, NULL); + vte_terminal_set_pty(terminal, NULL); /* Tell observers what's happened. */ - terminal->pvt->child_exit_status = status; - vte_terminal_emit_child_exited(terminal); + vte_terminal_emit_child_exited(terminal, status); g_object_thaw_notify(object); g_object_unref(object); @@ -3569,9 +3371,10 @@ _vte_terminal_disconnect_pty_write(VteTerminal *terminal) } /** - * vte_terminal_pty_new: + * vte_terminal_pty_new_sync: * @terminal: a #VteTerminal * @flags: flags from #VtePtyFlags + * @cancellable: (allow-none): a #GCancellable, or %NULL * @error: (allow-none): return location for a #GError, or %NULL * * Creates a new #VtePty, and sets the emulation property @@ -3580,21 +3383,20 @@ _vte_terminal_disconnect_pty_write(VteTerminal *terminal) * See vte_pty_new() for more information. * * Returns: (transfer full): a new #VtePty - * Since: 0.26 + * + * Since: 0.30 */ VtePty * -vte_terminal_pty_new(VteTerminal *terminal, - VtePtyFlags flags, - GError **error) +vte_terminal_pty_new_sync(VteTerminal *terminal, + VtePtyFlags flags, + GCancellable *cancellable, + GError **error) { - VteTerminalPrivate *pvt; VtePty *pty; g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); - pvt = terminal->pvt; - - pty = vte_pty_new(flags, error); + pty = vte_pty_new_sync(flags, cancellable, error); if (pty == NULL) return NULL; @@ -3608,12 +3410,11 @@ vte_terminal_pty_new(VteTerminal *terminal, * @terminal: a #VteTerminal * @child_pid: a #GPid * - * Watches @child_pid. When the process exists, the #VteReaper::child-exited - * signal will be called. Use vte_terminal_get_child_exit_status() to - * retrieve the child's exit status. + * Watches @child_pid. When the process exists, the #VteTerminal::child-exited + * signal will be called with the child's exit status. * * Prior to calling this function, a #VtePty must have been set in @terminal - * using vte_terminal_set_pty_object(). + * using vte_terminal_set_pty(). * When the child exits, the terminal's #VtePty will be set to %NULL. * * Note: g_child_watch_add() or g_child_watch_add_full() must not have @@ -3631,7 +3432,6 @@ vte_terminal_watch_child (VteTerminal *terminal, { VteTerminalPrivate *pvt; GObject *object; - VteReaper *reaper; g_return_if_fail(VTE_IS_TERMINAL(terminal)); g_return_if_fail(child_pid != -1); @@ -3647,25 +3447,16 @@ vte_terminal_watch_child (VteTerminal *terminal, /* Set this as the child's pid. */ pvt->pty_pid = child_pid; - pvt->child_exit_status = 0; /* Catch a child-exited signal from the child pid. */ - reaper = vte_reaper_get(); - vte_reaper_add_child(child_pid); - if (reaper != pvt->pty_reaper) { - if (terminal->pvt->pty_reaper != NULL) { - g_signal_handlers_disconnect_by_func(pvt->pty_reaper, - vte_terminal_catch_child_exited, - terminal); - g_object_unref(pvt->pty_reaper); - } - g_signal_connect(reaper, "child-exited", - G_CALLBACK(vte_terminal_catch_child_exited), - terminal); - pvt->pty_reaper = reaper; - } else { - g_object_unref(reaper); - } + if (terminal->pvt->child_watch_source != 0) { + g_source_remove (terminal->pvt->child_watch_source); + } + terminal->pvt->child_watch_source = + g_child_watch_add_full(G_PRIORITY_HIGH, + child_pid, + (GChildWatchFunc)vte_terminal_child_watch_cb, + terminal, NULL); /* FIXMEchpe: call vte_terminal_set_size here? */ @@ -3678,7 +3469,7 @@ vte_terminal_watch_child (VteTerminal *terminal, * Gets the user's shell, or %NULL. In the latter case, the * system default (usually "/bin/sh") should be used. * - * Returns: (tranfer full) (type filename): a newly allocated string with the + * Returns: (transfer full) (type filename): a newly allocated string with the * user's shell, or %NULL * * Since: 0.28 @@ -3695,129 +3486,8 @@ vte_get_user_shell (void) return NULL; } -static char * -_vte_terminal_get_user_shell_with_fallback (void) -{ - char *command; - const gchar *env; - - if ((command = vte_get_user_shell ())) - return command; - - if ((env = g_getenv ("SHELL"))) - return g_strdup (env); - - return g_strdup ("/bin/sh"); -} - -/* - * _vte_terminal_get_argv: - * @command: the command to run - * @argv: the argument vector - * @flags: (inout) flags from #GSpawnFlags - * - * Creates an argument vector to pass to g_spawn_async() from @command and - * @argv, modifying *@flags if necessary. - * Like __vte_pty_get_argv(), but returns the argument vector to spawn - * the user's shell if @command is %NULL. - * - * Returns: a newly allocated array of strings. Free with g_strfreev() - */ -static char ** -_vte_terminal_get_argv (const char *command, - char **argv, - GSpawnFlags *flags /* inout */) -{ - char **argv2; - char *shell = NULL; - - argv2 = __vte_pty_get_argv(command ? command : (shell = _vte_terminal_get_user_shell_with_fallback ()), - argv, - flags); - g_free(shell); - return argv2; -} - -/** - * vte_terminal_fork_command: - * @terminal: a #VteTerminal - * @command: (allow-none) (type filename): the name of a binary to run, or %NULL to spawn the user's shell - * @argv: (allow-none) (array zero-terminated=1) (element-type filename): the argument list to be passed to @command, or %NULL - * @envv: (allow-none) (array zero-terminated=1) (element-type filename): a list of environment variables to be added to the environment before - * starting @command, or %NULL - * @working_directory: (allow-none) (type filename): 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. The @argv and @envv lists should be %NULL-terminated, and - * argv[0] is expected to be the name of the file being run, as it would be if - * execve() were being called. 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. - * - * Note that all file descriptors except stdin/stdout/stderr will be closed - * before calling exec() in the child. - * - * Returns: the PID of the new process, or <literal>-1</literal> on failure - * - * Deprecated: 0.26: Use vte_terminal_fork_command_full() - */ -pid_t -vte_terminal_fork_command(VteTerminal *terminal, - const char *command, - char **argv, - char **envv, - const char *working_directory, - gboolean lastlog, - gboolean utmp, - gboolean wtmp) -{ - char **real_argv; - GSpawnFlags spawn_flags; - GPid child_pid; - gboolean ret; -#ifdef VTE_DEBUG - GError *error = NULL; - GError **err = &error; -#else - GError **err = NULL; -#endif - - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - - spawn_flags = G_SPAWN_CHILD_INHERITS_STDIN | - G_SPAWN_SEARCH_PATH; - real_argv = _vte_terminal_get_argv (command, argv, &spawn_flags); - - ret = vte_terminal_fork_command_full(terminal, - __vte_pty_get_pty_flags(lastlog, utmp, wtmp), - working_directory, - real_argv, - envv, - spawn_flags, - NULL, NULL, - &child_pid, - err); - g_strfreev (real_argv); - -#ifdef VTE_DEBUG - if (error) { - _vte_debug_print(VTE_DEBUG_MISC, - "vte_terminal_fork_command failed: %s\n", error->message); - g_error_free(error); - } -#endif - - if (!ret) - return -1; - - return (pid_t) child_pid; -} - /** - * vte_terminal_fork_command_full: + * vte_terminal_spawn_sync: * @terminal: a #VteTerminal * @pty_flags: flags from #VtePtyFlags * @working_directory: (allow-none): the name of a directory the command should start @@ -3826,9 +3496,10 @@ vte_terminal_fork_command(VteTerminal *terminal, * @envv: (allow-none) (array zero-terminated=1) (element-type filename): a list of environment * variables to be added to the environment before starting the process, or %NULL * @spawn_flags: flags from #GSpawnFlags - * @child_setup: (allow-none) (scope call): function to run in the child just before exec(), or %NULL + * @child_setup: (allow-none) (scope call): an extra child setup function to run in the child just before exec(), or %NULL * @child_setup_data: user data for @child_setup * @child_pid: (out) (allow-none) (transfer full): a location to store the child PID, or %NULL + * @cancellable: (allow-none): a #GCancellable, or %NULL * @error: (allow-none): return location for a #GError, or %NULL * * Starts the specified command under a newly-allocated controlling @@ -3847,10 +3518,10 @@ vte_terminal_fork_command(VteTerminal *terminal, * * Returns: %TRUE on success, or %FALSE on error with @error filled in * - * Since: 0.26 + * Since: 0.30 */ gboolean -vte_terminal_fork_command_full(VteTerminal *terminal, +vte_terminal_spawn_sync(VteTerminal *terminal, VtePtyFlags pty_flags, const char *working_directory, char **argv, @@ -3859,6 +3530,7 @@ vte_terminal_fork_command_full(VteTerminal *terminal, GSpawnChildSetupFunc child_setup, gpointer child_setup_data, GPid *child_pid /* out */, + GCancellable *cancellable, GError **error) { VtePty *pty; @@ -3869,7 +3541,7 @@ vte_terminal_fork_command_full(VteTerminal *terminal, g_return_val_if_fail(child_setup_data == NULL || child_setup, FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); - pty = vte_pty_new(pty_flags, error); + pty = vte_terminal_pty_new_sync(terminal, pty_flags, cancellable, error); if (pty == NULL) return FALSE; @@ -3888,7 +3560,7 @@ vte_terminal_fork_command_full(VteTerminal *terminal, return FALSE; } - vte_terminal_set_pty_object(terminal, pty); + vte_terminal_set_pty(terminal, pty); vte_terminal_watch_child(terminal, pid); g_object_unref (pty); @@ -3898,66 +3570,6 @@ vte_terminal_fork_command_full(VteTerminal *terminal, return TRUE; } -/** - * 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 - * @working_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. - * - * Note that all file descriptors except stdin/stdout/stderr will be closed - * in the child. - * - * Note that @envv and @working_directory are silently ignored. - * - * 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 - * - * Deprecated: 0.26: Use #VtePty and fork() instead - */ -pid_t -vte_terminal_forkpty(VteTerminal *terminal, - char **envv, const char *working_directory, - gboolean lastlog, gboolean utmp, gboolean wtmp) -{ -#ifdef HAVE_FORK - VtePty *pty; - GPid pid; - - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - - pty = vte_pty_new(__vte_pty_get_pty_flags(lastlog, utmp, wtmp), NULL); - if (pty == NULL) - return FALSE; - - if (!__vte_pty_fork(pty, - &pid, - NULL)) { - g_object_unref(pty); - return FALSE; - } - - vte_terminal_set_pty_object(terminal, pty); - // FIXMEchpe is that really right? - vte_terminal_watch_child(terminal, pid); - - return pid; -#else - return -1; -#endif -} - /* Handle an EOF from the client. */ static void vte_terminal_eof(GIOChannel *channel, VteTerminal *terminal) @@ -3966,7 +3578,7 @@ vte_terminal_eof(GIOChannel *channel, VteTerminal *terminal) g_object_freeze_notify(object); - vte_terminal_set_pty_object(terminal, NULL); + vte_terminal_set_pty(terminal, NULL); /* Emit a signal that we read an EOF. */ vte_terminal_queue_eof(terminal); @@ -4055,6 +3667,7 @@ vte_terminal_process_incoming(VteTerminal *terminal) long wcount, start, delta; gboolean leftovers, modified, bottom, again; gboolean invalidated_text; + gboolean in_scroll_region; GArray *unichars; struct _vte_incoming_chunk *chunk, *next_chunk, *achunk = NULL; @@ -4074,6 +3687,10 @@ vte_terminal_process_incoming(VteTerminal *terminal) cursor = screen->cursor_current; cursor_visible = terminal->pvt->cursor_visible; + in_scroll_region = screen->scrolling_restricted + && (screen->cursor_current.row >= (screen->insert_delta + screen->scrolling_region.start)) + && (screen->cursor_current.row <= (screen->insert_delta + screen->scrolling_region.end)); + /* We should only be called when there's data to process. */ g_assert(terminal->pvt->incoming || (terminal->pvt->pending->len > 0)); @@ -4172,6 +3789,8 @@ skip_chunk: * points to the first character which isn't part of this * sequence. */ if ((match != NULL) && (match[0] != '\0')) { + gboolean new_in_scroll_region; + /* Call the right sequence handler for the requested * behavior. */ _vte_terminal_handle_sequence(terminal, @@ -4182,20 +3801,29 @@ skip_chunk: start = (next - wbuf); modified = TRUE; - /* if we have moved during the sequence handler, restart the bbox */ + new_in_scroll_region = screen->scrolling_restricted + && (screen->cursor_current.row >= (screen->insert_delta + screen->scrolling_region.start)) + && (screen->cursor_current.row <= (screen->insert_delta + screen->scrolling_region.end)); + + delta = screen->scroll_delta; /* delta may have changed from sequence. */ + + /* if we have moved greatly during the sequence handler, or moved + * into a scroll_region from outside it, restart the bbox. + */ if (invalidated_text && - (screen->cursor_current.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK || - screen->cursor_current.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK || - screen->cursor_current.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK || - screen->cursor_current.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK)) { + ((new_in_scroll_region && !in_scroll_region) || + (screen->cursor_current.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK || + screen->cursor_current.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK || + screen->cursor_current.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK || + screen->cursor_current.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK))) { /* Clip off any part of the box which isn't already on-screen. */ bbox_topleft.x = MAX(bbox_topleft.x, 0); bbox_topleft.y = MAX(bbox_topleft.y, delta); bbox_bottomright.x = MIN(bbox_bottomright.x, - terminal->column_count); + terminal->pvt->column_count); /* lazily apply the +1 to the cursor_row */ bbox_bottomright.y = MIN(bbox_bottomright.y + 1, - delta + terminal->row_count); + delta + terminal->pvt->row_count); _vte_invalidate_cells(terminal, bbox_topleft.x, @@ -4207,6 +3835,8 @@ skip_chunk: bbox_bottomright.x = bbox_bottomright.y = -G_MAXINT; bbox_topleft.x = bbox_topleft.y = G_MAXINT; } + + in_scroll_region = new_in_scroll_region; } else /* Second, we have a NULL match, and next points to the very * next character in the buffer. Insert the character which @@ -4285,10 +3915,10 @@ skip_chunk: bbox_topleft.x = MAX(bbox_topleft.x, 0); bbox_topleft.y = MAX(bbox_topleft.y, delta); bbox_bottomright.x = MIN(bbox_bottomright.x, - terminal->column_count); + terminal->pvt->column_count); /* lazily apply the +1 to the cursor_row */ bbox_bottomright.y = MIN(bbox_bottomright.y + 1, - delta + terminal->row_count); + delta + terminal->pvt->row_count); _vte_invalidate_cells(terminal, bbox_topleft.x, @@ -4380,7 +4010,7 @@ next_match: terminal->pvt->selection_start.row, 0, terminal->pvt->selection_end.row, - terminal->column_count, + terminal->pvt->column_count, vte_cell_is_selected, NULL, NULL); @@ -4405,10 +4035,10 @@ next_match: bbox_topleft.x = MAX(bbox_topleft.x, 0); bbox_topleft.y = MAX(bbox_topleft.y, delta); bbox_bottomright.x = MIN(bbox_bottomright.x, - terminal->column_count); + terminal->pvt->column_count); /* lazily apply the +1 to the cursor_row */ bbox_bottomright.y = MIN(bbox_bottomright.y + 1, - delta + terminal->row_count); + delta + terminal->pvt->row_count); _vte_invalidate_cells(terminal, bbox_topleft.x, @@ -4436,11 +4066,11 @@ next_match: if (gtk_widget_get_realized (&terminal->widget)) { GdkRectangle rect; rect.x = terminal->pvt->screen->cursor_current.col * - terminal->char_width + terminal->pvt->inner_border.left; - rect.width = terminal->char_width; + terminal->pvt->char_width + terminal->pvt->padding.left; + rect.width = terminal->pvt->char_width; rect.y = (terminal->pvt->screen->cursor_current.row - delta) * - terminal->char_height + terminal->pvt->inner_border.top; - rect.height = terminal->char_height; + terminal->pvt->char_height + terminal->pvt->padding.top; + rect.height = terminal->pvt->char_height; gtk_im_context_set_cursor_location(terminal->pvt->im_context, &rect); } @@ -4519,7 +4149,7 @@ vte_terminal_io_read(GIOChannel *channel, if (max_bytes) { max_bytes = terminal->pvt->max_input_bytes / max_bytes; } else { - max_bytes = VTE_MAX_INPUT_READ; + max_bytes = terminal->pvt->max_input_bytes; } bytes = terminal->pvt->input_bytes; @@ -4563,9 +4193,14 @@ out: _vte_terminal_feed_chunks (terminal, chunks); } if (!vte_terminal_is_processing (terminal)) { - GDK_THREADS_ENTER (); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_enter (); + G_GNUC_END_IGNORE_DEPRECATIONS; + vte_terminal_add_process_timeout (terminal); - GDK_THREADS_LEAVE (); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_leave (); + G_GNUC_END_IGNORE_DEPRECATIONS; } terminal->pvt->pty_input_active = len != 0; terminal->pvt->input_bytes = bytes; @@ -4598,9 +4233,15 @@ out: if (eof) { /* potential deadlock ... */ if (!vte_terminal_is_processing (terminal)) { - GDK_THREADS_ENTER (); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_enter (); + G_GNUC_END_IGNORE_DEPRECATIONS; + vte_terminal_eof (channel, terminal); - GDK_THREADS_LEAVE (); + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_leave (); + G_GNUC_END_IGNORE_DEPRECATIONS; } else { vte_terminal_eof (channel, terminal); } @@ -4614,7 +4255,7 @@ out: /** * vte_terminal_feed: * @terminal: a #VteTerminal - * @data: a string in the terminal's current encoding + * @data: (array length=length) (element-type guint8): a string in the terminal's current encoding * @length: the length of the string * * Interprets @data as if it were data received from a child process. This @@ -4670,7 +4311,7 @@ vte_terminal_io_write(GIOChannel *channel, fd = g_io_channel_unix_get_fd(channel); count = write(fd, terminal->pvt->outgoing->data, - _vte_buffer_length(terminal->pvt->outgoing)); + _vte_byte_array_length(terminal->pvt->outgoing)); if (count != -1) { _VTE_DEBUG_IF (VTE_DEBUG_IO) { gssize i; @@ -4683,10 +4324,10 @@ vte_terminal_io_write(GIOChannel *channel, ((guint8)terminal->pvt->outgoing->data[i]) + 64); } } - _vte_buffer_consume(terminal->pvt->outgoing, count); + _vte_byte_array_consume(terminal->pvt->outgoing, count); } - if (_vte_buffer_length(terminal->pvt->outgoing) == 0) { + if (_vte_byte_array_length(terminal->pvt->outgoing) == 0) { leave_open = FALSE; } else { leave_open = TRUE; @@ -4723,7 +4364,7 @@ vte_terminal_send(VteTerminal *terminal, const char *encoding, icount = length; ibuf = data; ocount = ((length + 1) * VTE_UTF8_BPC) + 1; - _vte_buffer_set_minimum_size(terminal->pvt->conv_buffer, ocount); + _vte_byte_array_set_minimum_size(terminal->pvt->conv_buffer, ocount); obuf = obufptr = terminal->pvt->conv_buffer->data; if (_vte_conv(conv, &ibuf, &icount, &obuf, &ocount) == (gsize)-1) { @@ -4785,7 +4426,7 @@ vte_terminal_send(VteTerminal *terminal, const char *encoding, /* If there's a place for it to go, add the data to the * outgoing buffer. */ if ((cooked_length > 0) && (terminal->pvt->pty != NULL)) { - _vte_buffer_append(terminal->pvt->outgoing, + _vte_byte_array_append(terminal->pvt->outgoing, cooked, cooked_length); _VTE_DEBUG_IF(VTE_DEBUG_KEYBOARD) { for (i = 0; i < cooked_length; i++) { @@ -4859,7 +4500,7 @@ vte_terminal_feed_child_binary(VteTerminal *terminal, const char *data, glong le /* If there's a place for it to go, add the data to the * outgoing buffer. */ if (terminal->pvt->pty != NULL) { - _vte_buffer_append(terminal->pvt->outgoing, + _vte_byte_array_append(terminal->pvt->outgoing, data, length); /* If we need to start waiting for the child pty to * become available for writing, set that up here. */ @@ -4944,90 +4585,40 @@ vte_terminal_im_preedit_changed(GtkIMContext *im_context, VteTerminal *terminal) _vte_invalidate_cursor_once(terminal, FALSE); } -/* Handle the toplevel being reconfigured. */ -static gboolean -vte_terminal_configure_toplevel(VteTerminal *terminal) -{ - _vte_debug_print(VTE_DEBUG_EVENTS, "Top level parent configured.\n"); - - 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; -} - -/* Handle a hierarchy-changed signal. */ static void -vte_terminal_hierarchy_changed(GtkWidget *widget, GtkWidget *old_toplevel, - gpointer data) -{ - GtkWidget *toplevel; - - _vte_debug_print(VTE_DEBUG_EVENTS, "Hierarchy changed.\n"); - if (old_toplevel != NULL) { - g_signal_handlers_disconnect_by_func(old_toplevel, - vte_terminal_configure_toplevel, - widget); - } - - toplevel = gtk_widget_get_toplevel(widget); - if (toplevel != NULL) { - g_signal_connect_swapped (toplevel, "configure-event", - G_CALLBACK (vte_terminal_configure_toplevel), - widget); - } -} - -static void -vte_terminal_set_inner_border(VteTerminal *terminal) +vte_terminal_set_padding(VteTerminal *terminal) { VteTerminalPrivate *pvt = terminal->pvt; GtkWidget *widget = GTK_WIDGET(terminal); - GtkBorder *border = NULL; - GtkBorder inner_border; - - gtk_widget_style_get(widget, "inner-border", &border, NULL); + GtkBorder padding; - if (border != NULL) { - inner_border = *border; - gtk_border_free(border); - } else { - inner_border = default_inner_border; - } + gtk_style_context_get_padding(gtk_widget_get_style_context(widget), + gtk_widget_get_state_flags(widget), + &padding); _vte_debug_print(VTE_DEBUG_MISC, - "Setting inner-border to { %d, %d, %d, %d }\n", - inner_border.left, inner_border.right, - inner_border.top, inner_border.bottom); + "Setting padding to (%d,%d,%d,%d)\n", + padding.left, padding.right, + padding.top, padding.bottom); - if (memcmp(&inner_border, &pvt->inner_border, sizeof(GtkBorder)) == 0) + if (memcmp(&padding, &pvt->padding, sizeof(GtkBorder)) == 0) return; - pvt->inner_border = inner_border; + pvt->padding = padding; gtk_widget_queue_resize(widget); } static void -vte_terminal_style_set (GtkWidget *widget, - GtkStyle *prev_style) +vte_terminal_style_updated (GtkWidget *widget) { VteTerminal *terminal = VTE_TERMINAL(widget); float aspect; - GTK_WIDGET_CLASS (vte_terminal_parent_class)->style_set (widget, prev_style); + GTK_WIDGET_CLASS (vte_terminal_parent_class)->style_updated (widget); - if (gtk_widget_get_style(widget) == prev_style) - return; - - vte_terminal_set_font_full_internal(terminal, terminal->pvt->fontdesc, - terminal->pvt->fontantialias); - - vte_terminal_set_inner_border(terminal); + vte_terminal_set_font(terminal, terminal->pvt->fontdesc); + vte_terminal_set_padding(terminal); gtk_widget_style_get(widget, "cursor-aspect-ratio", &aspect, NULL); if (aspect != terminal->pvt->cursor_aspect_ratio) { @@ -5085,28 +4676,9 @@ _vte_terminal_audible_beep(VteTerminal *terminal) void _vte_terminal_visible_beep(VteTerminal *terminal) { - GtkWidget *widget; - GtkAllocation allocation; - GtkStyle *style; - PangoColor color; - - widget = &terminal->widget; + GtkWidget *widget = &terminal->widget; if (gtk_widget_get_realized (widget)) { - - style = gtk_widget_get_style (widget); - gtk_widget_get_allocation (widget, &allocation); - color.red = style->fg[gtk_widget_get_state (widget)].red; - color.green = style->fg[gtk_widget_get_state (widget)].green; - color.blue = style->fg[gtk_widget_get_state (widget)].blue; - - _vte_draw_start(terminal->pvt->draw); - _vte_draw_fill_rectangle(terminal->pvt->draw, - 0, 0, - allocation.width, allocation.height, - &color, VTE_DRAW_OPAQUE); - _vte_draw_end(terminal->pvt->draw); - /* Force the repaint, max delay of UPDATE_REPEAT_TIMEOUT */ _vte_invalidate_all (terminal); } @@ -5134,11 +4706,7 @@ vte_translate_ctrlkey (GdkEventKey *event) if (event->keyval < 128) return event->keyval; -#if GTK_CHECK_VERSION (2, 90, 8) keymap = gdk_keymap_get_for_display(gdk_window_get_display (event->window)); -#else - keymap = gdk_keymap_get_for_display(gdk_drawable_get_display (event->window)); -#endif /* Try groups in order to find one mapping the key to ASCII */ for (i = 0; i < 4; i++) { @@ -5163,19 +4731,24 @@ static void vte_terminal_read_modifiers (VteTerminal *terminal, GdkEvent *event) { + GdkKeymap *keymap; GdkModifierType modifiers; /* Read the modifiers. */ - if (gdk_event_get_state((GdkEvent*)event, &modifiers)) { - GdkKeymap *keymap; -#if GTK_CHECK_VERSION (2, 90, 8) - keymap = gdk_keymap_get_for_display(gdk_window_get_display(((GdkEventAny*)event)->window)); -#else - keymap = gdk_keymap_get_for_display(gdk_drawable_get_display(((GdkEventAny*)event)->window)); + if (!gdk_event_get_state((GdkEvent*)event, &modifiers)) + return; + + keymap = gdk_keymap_get_for_display(gdk_window_get_display(((GdkEventAny*)event)->window)); + + gdk_keymap_add_virtual_modifiers (keymap, &modifiers); + +#if 1 + /* HACK! Treat ALT as META; see bug #663779. */ + if (modifiers & GDK_MOD1_MASK) + modifiers |= VTE_META_MASK; #endif - gdk_keymap_add_virtual_modifiers (keymap, &modifiers); - terminal->pvt->modifiers = modifiers; - } + + terminal->pvt->modifiers = modifiers; } /* Read and handle a keypress event. */ @@ -5220,7 +4793,7 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) if (terminal->pvt->margin_bell) { if ((terminal->pvt->screen->cursor_current.col + (glong) terminal->pvt->bell_margin) == - terminal->column_count) { + terminal->pvt->column_count) { _vte_terminal_beep (terminal); } } @@ -5249,11 +4822,11 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) /* We steal many keypad keys here. */ if (!terminal->pvt->im_preedit_active) { switch (keyval) { - case GDK_KEY (KP_Add): - case GDK_KEY (KP_Subtract): - case GDK_KEY (KP_Multiply): - case GDK_KEY (KP_Divide): - case GDK_KEY (KP_Enter): + case GDK_KEY_KP_Add: + case GDK_KEY_KP_Subtract: + case GDK_KEY_KP_Multiply: + case GDK_KEY_KP_Divide: + case GDK_KEY_KP_Enter: steal = TRUE; break; default: @@ -5263,27 +4836,68 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) steal = TRUE; } switch (keyval) { - case GDK_KEY (Multi_key): - case GDK_KEY (Codeinput): - case GDK_KEY (SingleCandidate): - case GDK_KEY (MultipleCandidate): - case GDK_KEY (PreviousCandidate): - case GDK_KEY (Kanji): - case GDK_KEY (Muhenkan): - case GDK_KEY (Henkan): - case GDK_KEY (Romaji): - case GDK_KEY (Hiragana): - case GDK_KEY (Katakana): - case GDK_KEY (Hiragana_Katakana): - case GDK_KEY (Zenkaku): - case GDK_KEY (Hankaku): - case GDK_KEY (Zenkaku_Hankaku): - case GDK_KEY (Touroku): - case GDK_KEY (Massyo): - case GDK_KEY (Kana_Lock): - case GDK_KEY (Kana_Shift): - case GDK_KEY (Eisu_Shift): - case GDK_KEY (Eisu_toggle): + case GDK_KEY_ISO_Lock: + case GDK_KEY_ISO_Level2_Latch: + case GDK_KEY_ISO_Level3_Shift: + case GDK_KEY_ISO_Level3_Latch: + case GDK_KEY_ISO_Level3_Lock: + case GDK_KEY_ISO_Level5_Shift: + case GDK_KEY_ISO_Level5_Latch: + case GDK_KEY_ISO_Level5_Lock: + case GDK_KEY_ISO_Group_Shift: + case GDK_KEY_ISO_Group_Latch: + case GDK_KEY_ISO_Group_Lock: + case GDK_KEY_ISO_Next_Group: + case GDK_KEY_ISO_Next_Group_Lock: + case GDK_KEY_ISO_Prev_Group: + case GDK_KEY_ISO_Prev_Group_Lock: + case GDK_KEY_ISO_First_Group: + case GDK_KEY_ISO_First_Group_Lock: + case GDK_KEY_ISO_Last_Group: + case GDK_KEY_ISO_Last_Group_Lock: + case GDK_KEY_Multi_key: + case GDK_KEY_Codeinput: + case GDK_KEY_SingleCandidate: + case GDK_KEY_MultipleCandidate: + case GDK_KEY_PreviousCandidate: + case GDK_KEY_Kanji: + case GDK_KEY_Muhenkan: + case GDK_KEY_Henkan_Mode: + /* case GDK_KEY_Henkan: is GDK_KEY_Henkan_Mode */ + case GDK_KEY_Romaji: + case GDK_KEY_Hiragana: + case GDK_KEY_Katakana: + case GDK_KEY_Hiragana_Katakana: + case GDK_KEY_Zenkaku: + case GDK_KEY_Hankaku: + case GDK_KEY_Zenkaku_Hankaku: + case GDK_KEY_Touroku: + case GDK_KEY_Massyo: + case GDK_KEY_Kana_Lock: + case GDK_KEY_Kana_Shift: + case GDK_KEY_Eisu_Shift: + case GDK_KEY_Eisu_toggle: + /* case GDK_KEY_Kanji_Bangou: is GDK_KEY_Codeinput */ + /* case GDK_KEY_Zen_Koho: is GDK_KEY_MultipleCandidate */ + /* case GDK_KEY_Mae_Koho: is GDK_KEY_PreviousCandidate */ + /* case GDK_KEY_kana_switch: is GDK_KEY_ISO_Group_Shift */ + case GDK_KEY_Hangul: + case GDK_KEY_Hangul_Start: + case GDK_KEY_Hangul_End: + case GDK_KEY_Hangul_Hanja: + case GDK_KEY_Hangul_Jamo: + case GDK_KEY_Hangul_Romaja: + /* case GDK_KEY_Hangul_Codeinput: is GDK_KEY_Codeinput */ + case GDK_KEY_Hangul_Jeonja: + case GDK_KEY_Hangul_Banja: + case GDK_KEY_Hangul_PreHanja: + case GDK_KEY_Hangul_PostHanja: + /* case GDK_KEY_Hangul_SingleCandidate: is GDK_KEY_SingleCandidate */ + /* case GDK_KEY_Hangul_MultipleCandidate: is GDK_KEY_MultipleCandidate */ + /* case GDK_KEY_Hangul_PreviousCandidate: is GDK_KEY_PreviousCandidate */ + case GDK_KEY_Hangul_Special: + /* case GDK_KEY_Hangul_switch: is GDK_KEY_ISO_Group_Shift */ + steal = FALSE; break; default: @@ -5309,7 +4923,7 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) handled = FALSE; /* Map the key to a sequence name if we can. */ switch (keyval) { - case GDK_KEY (BackSpace): + case GDK_KEY_BackSpace: switch (terminal->pvt->backspace_binding) { case VTE_ERASE_ASCII_BACKSPACE: normal = g_strdup(""); @@ -5357,8 +4971,8 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) } handled = TRUE; break; - case GDK_KEY (KP_Delete): - case GDK_KEY (Delete): + case GDK_KEY_KP_Delete: + case GDK_KEY_Delete: switch (terminal->pvt->delete_binding) { case VTE_ERASE_ASCII_BACKSPACE: normal = g_strdup("\010"); @@ -5386,8 +5000,8 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) handled = TRUE; suppress_meta_esc = TRUE; break; - case GDK_KEY (KP_Insert): - case GDK_KEY (Insert): + case GDK_KEY_KP_Insert: + case GDK_KEY_Insert: if (modifiers & GDK_SHIFT_MASK) { if (modifiers & GDK_CONTROL_MASK) { vte_terminal_paste_clipboard(terminal); @@ -5405,9 +5019,10 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) } break; /* Keypad/motion keys. */ - case GDK_KEY (KP_Up): - case GDK_KEY (Up): - if (modifiers & GDK_CONTROL_MASK + case GDK_KEY_KP_Up: + case GDK_KEY_Up: + if (terminal->pvt->screen == &terminal->pvt->normal_screen + && modifiers & GDK_CONTROL_MASK && modifiers & GDK_SHIFT_MASK) { vte_terminal_scroll_lines(terminal, -1); scrolled = TRUE; @@ -5415,9 +5030,10 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) suppress_meta_esc = TRUE; } break; - case GDK_KEY (KP_Down): - case GDK_KEY (Down): - if (modifiers & GDK_CONTROL_MASK + case GDK_KEY_KP_Down: + case GDK_KEY_Down: + if (terminal->pvt->screen == &terminal->pvt->normal_screen + && modifiers & GDK_CONTROL_MASK && modifiers & GDK_SHIFT_MASK) { vte_terminal_scroll_lines(terminal, 1); scrolled = TRUE; @@ -5425,52 +5041,56 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) suppress_meta_esc = TRUE; } break; - case GDK_KEY (KP_Page_Up): - case GDK_KEY (Page_Up): - if (modifiers & GDK_SHIFT_MASK) { + case GDK_KEY_KP_Page_Up: + case GDK_KEY_Page_Up: + if (terminal->pvt->screen == &terminal->pvt->normal_screen + && modifiers & GDK_SHIFT_MASK) { vte_terminal_scroll_pages(terminal, -1); scrolled = TRUE; handled = TRUE; suppress_meta_esc = TRUE; } break; - case GDK_KEY (KP_Page_Down): - case GDK_KEY (Page_Down): - if (modifiers & GDK_SHIFT_MASK) { + case GDK_KEY_KP_Page_Down: + case GDK_KEY_Page_Down: + if (terminal->pvt->screen == &terminal->pvt->normal_screen + && modifiers & GDK_SHIFT_MASK) { vte_terminal_scroll_pages(terminal, 1); scrolled = TRUE; handled = TRUE; suppress_meta_esc = TRUE; } break; - case GDK_KEY (KP_Home): - case GDK_KEY (Home): - if (modifiers & GDK_SHIFT_MASK) { + case GDK_KEY_KP_Home: + case GDK_KEY_Home: + if (terminal->pvt->screen == &terminal->pvt->normal_screen + && modifiers & GDK_SHIFT_MASK) { vte_terminal_maybe_scroll_to_top(terminal); scrolled = TRUE; handled = TRUE; } break; - case GDK_KEY (KP_End): - case GDK_KEY (End): - if (modifiers & GDK_SHIFT_MASK) { + case GDK_KEY_KP_End: + case GDK_KEY_End: + if (terminal->pvt->screen == &terminal->pvt->normal_screen + && modifiers & GDK_SHIFT_MASK) { vte_terminal_maybe_scroll_to_bottom(terminal); scrolled = TRUE; handled = TRUE; } break; /* Let Shift +/- tweak the font, like XTerm does. */ - case GDK_KEY (KP_Add): - case GDK_KEY (KP_Subtract): + case GDK_KEY_KP_Add: + case GDK_KEY_KP_Subtract: if (modifiers & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { switch (keyval) { - case GDK_KEY (KP_Add): + case GDK_KEY_KP_Add: vte_terminal_emit_increase_font_size(terminal); handled = TRUE; suppress_meta_esc = TRUE; break; - case GDK_KEY (KP_Subtract): + case GDK_KEY_KP_Subtract: vte_terminal_emit_decrease_font_size(terminal); handled = TRUE; suppress_meta_esc = TRUE; @@ -5493,7 +5113,7 @@ vte_terminal_key_press(GtkWidget *widget, GdkEventKey *event) terminal->pvt->keypad_mode == VTE_KEYMODE_APPLICATION, terminal->pvt->termcap, terminal->pvt->emulation ? - terminal->pvt->emulation : vte_terminal_get_default_emulation(terminal), + terminal->pvt->emulation : vte_get_default_emulation(), &normal, &normal_length, &special); @@ -5610,8 +5230,8 @@ vte_terminal_key_release(GtkWidget *widget, GdkEventKey *event) && gtk_im_context_filter_keypress (terminal->pvt->im_context, event); } -/** - * vte_terminal_is_word_char: +/* + * _vte_terminal_is_word_char: * @terminal: a #VteTerminal * @c: a candidate Unicode code point * @@ -5621,32 +5241,11 @@ vte_terminal_key_release(GtkWidget *widget, GdkEventKey *event) * Returns: %TRUE if the character is considered to be part of a word */ gboolean -vte_terminal_is_word_char(VteTerminal *terminal, gunichar c) +_vte_terminal_is_word_char(VteTerminal *terminal, gunichar c) { - guint i; - VteWordCharRange *range; - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE); - - if (terminal->pvt->word_chars != NULL) { - /* Go through each range and check if c is included. */ - for (i = 0; i < terminal->pvt->word_chars->len; i++) { - range = &g_array_index(terminal->pvt->word_chars, - VteWordCharRange, - i); - if ((c >= range->start) && (c <= range->end)) - return TRUE; - } - } - - /* If not ASCII, or ASCII and no array set (or empty array), - * fall back on Unicode properties. */ - return (c >= 0x80 || - (terminal->pvt->word_chars == NULL) || - (terminal->pvt->word_chars->len == 0)) && - g_unichar_isgraph(c) && - !g_unichar_ispunct(c) && - !g_unichar_isspace(c) && - (c != '\0'); + return g_unichar_isgraph(c) && + (g_unichar_isalnum(c) || + g_unichar_ispunct(c)); } /* Check if the characters in the two given locations are in the same class @@ -5658,7 +5257,7 @@ vte_same_class(VteTerminal *terminal, glong acol, glong arow, const VteCell *pcell = NULL; gboolean word_char; if ((pcell = vte_terminal_find_charcell(terminal, acol, arow)) != NULL && pcell->c != 0) { - word_char = vte_terminal_is_word_char(terminal, _vte_unistr_get_base (pcell->c)); + word_char = _vte_terminal_is_word_char(terminal, _vte_unistr_get_base (pcell->c)); /* Lets not group non-wordchars together (bug #25290) */ if (!word_char) @@ -5668,7 +5267,7 @@ vte_same_class(VteTerminal *terminal, glong acol, glong arow, if (pcell == NULL || pcell->c == 0) { return FALSE; } - if (word_char != vte_terminal_is_word_char(terminal, _vte_unistr_get_base (pcell->c))) { + if (word_char != _vte_terminal_is_word_char(terminal, _vte_unistr_get_base (pcell->c))) { return FALSE; } return TRUE; @@ -5814,22 +5413,88 @@ vte_terminal_paste_cb(GtkClipboard *clipboard, const gchar *text, gpointer data) } } +/** + * _vte_terminal_xy_to_grid: + * @x: the X coordinate + * @y: the Y coordinate + * @col: return location to store the column + * @row: return location to store the row + * + * Translates from widget coordinates to grid coordinates. + * + * If the coordinates are outside the grid, returns %FALSE. + */ +gboolean +_vte_terminal_xy_to_grid(VteTerminal *terminal, + long x, + long y, + long *col, + long *row) +{ + VteTerminalPrivate *pvt = terminal->pvt; + long c, r; + + /* FIXMEchpe: is this correct for RTL? */ + c = (x - pvt->padding.left) / pvt->char_width; + r = (y - pvt->padding.top) / pvt->char_height; + + if ((c < 0 || c >= pvt->column_count) || + (r < 0 || r >= pvt->row_count)) + return FALSE; + + *col = c; + *row = r; + return TRUE; +} + +/* + * _vte_terminal_size_to_grid_size: + * @w: the width in px + * @h: the height in px + * @col: return location to store the column count + * @row: return location to store the row count + * + * Translates from widget size to grid size. + * + * If the given width or height are insufficient to show even + * one column or row (i.e due to padding), returns %FALSE. + */ +gboolean +_vte_terminal_size_to_grid_size(VteTerminal *terminal, + long w, + long h, + long *cols, + long *rows) +{ + VteTerminalPrivate *pvt = terminal->pvt; + long n_cols, n_rows; + + n_cols = (w - pvt->padding.left - pvt->padding.right) / pvt->char_width; + n_rows = (h - pvt->padding.top -pvt->padding.bottom) / pvt->char_height; + + if (n_cols <= 0 || n_rows <= 0) + return FALSE; + + *cols = n_cols; + *rows = n_rows; + return TRUE; +} + static void -vte_terminal_get_mouse_tracking_info (VteTerminal *terminal, - int button, - long col, - long row, - unsigned char *pb, - unsigned char *px, - unsigned char *py) +vte_terminal_feed_mouse_event(VteTerminal *terminal, + int button, + gboolean is_drag, + gboolean is_release, + long col, + long row) { - unsigned char cb = 0, cx = 0, cy = 0; + unsigned char cb = 0; + long cx, cy; + char buf[LINE_MAX]; + gint len = 0; /* Encode the button information in cb. */ switch (button) { - case 0: /* Release/no buttons. */ - cb = 3; - break; case 1: /* Left. */ cb = 0; break; @@ -5846,7 +5511,12 @@ vte_terminal_get_mouse_tracking_info (VteTerminal *terminal, cb = 65; /* Scroll down. */ break; } - cb += 32; /* 32 for normal */ + + /* With the exception of the 1006 mode, button release is also encoded here. */ + /* Note that if multiple extensions are enabled, the 1006 is used, so it's okay to check for only that. */ + if (is_release && !terminal->pvt->mouse_xterm_extension) { + cb = 3; + } /* Encode the modifiers. */ if (terminal->pvt->modifiers & GDK_SHIFT_MASK) { @@ -5859,42 +5529,59 @@ vte_terminal_get_mouse_tracking_info (VteTerminal *terminal, cb |= 16; } - /* Encode the cursor coordinates. */ - cx = 32 + CLAMP(1 + col, - 1, terminal->column_count); - cy = 32 + CLAMP(1 + row, - 1, terminal->row_count);; + /* Encode a drag event. */ + if (is_drag) { + cb |= 32; + } + + /* Clamp the cursor coordinates. Make them 1-based. */ + cx = CLAMP(1 + col, + 1, terminal->pvt->column_count); + cy = CLAMP(1 + row, + 1, terminal->pvt->row_count); - *pb = cb; - *px = cx; - *py = cy; + /* Check the extensions in decreasing order of preference. Encoding the release event above assumes that 1006 comes first. */ + if (terminal->pvt->mouse_xterm_extension) { + /* xterm's extended mode (1006) */ + len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "<%d;%ld;%ld%c", cb, cx, cy, is_release ? 'm' : 'M'); + } else if (terminal->pvt->mouse_urxvt_extension) { + /* urxvt's extended mode (1015) */ + len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "%d;%ld;%ldM", 32 + cb, cx, cy); + } else if (cx <= 231 && cy <= 231) { + /* legacy mode */ + len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "M%c%c%c", 32 + cb, 32 + (guchar)cx, 32 + (guchar)cy); + } + + /* Send event direct to the child, this is binary not text data */ + vte_terminal_feed_child_binary(terminal, buf, len); } static void vte_terminal_send_mouse_button_internal(VteTerminal *terminal, int button, + gboolean is_release, long x, long y) { - unsigned char cb, cx, cy; - char buf[LINE_MAX]; - gint len; - int width = terminal->char_width; - int height = terminal->char_height; - long col = (x - terminal->pvt->inner_border.left) / width; - long row = (y - terminal->pvt->inner_border.top) / height; + int width = terminal->pvt->char_width; + int height = terminal->pvt->char_height; + long col = (x - terminal->pvt->padding.left) / width; + long row = (y - terminal->pvt->padding.top) / height; - vte_terminal_get_mouse_tracking_info (terminal, - button, col, row, - &cb, &cx, &cy); - - /* Send event direct to the child, this is binary not text data */ - len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "M%c%c%c", cb, cx, cy); - vte_terminal_feed_child_binary(terminal, buf, len); + vte_terminal_feed_mouse_event(terminal, button, FALSE /* not drag */, is_release, col, row); } -/* Send a mouse button click/release notification. */ -static void +/* + * vte_terminal_maybe_send_mouse_button: + * @terminal: + * @event: + * + * Sends a mouse button click or release notification to the application, + * if the terminal is in mouse tracking mode. + * + * Returns: %TRUE iff the event was consumed + */ +static gboolean vte_terminal_maybe_send_mouse_button(VteTerminal *terminal, GdkEventButton *event) { @@ -5903,68 +5590,72 @@ vte_terminal_maybe_send_mouse_button(VteTerminal *terminal, switch (event->type) { case GDK_BUTTON_PRESS: if (terminal->pvt->mouse_tracking_mode < MOUSE_TRACKING_SEND_XY_ON_CLICK) { - return; + return FALSE; } break; case GDK_BUTTON_RELEASE: { if (terminal->pvt->mouse_tracking_mode < MOUSE_TRACKING_SEND_XY_ON_BUTTON) { - return; + return FALSE; } break; } default: - return; + return FALSE; break; } vte_terminal_send_mouse_button_internal(terminal, - (event->type == GDK_BUTTON_PRESS) ? event->button : 0, + event->button, + event->type == GDK_BUTTON_RELEASE, event->x, event->y); + return TRUE; } -/* Send a mouse motion notification. */ -static void +/* + * vte_terminal_maybe_send_mouse_drag: + * @terminal: + * @event: + * + * Sends a mouse motion notification to the application, + * if the terminal is in mouse tracking mode. + * + * Returns: %TRUE iff the event was consumed + */ +static gboolean vte_terminal_maybe_send_mouse_drag(VteTerminal *terminal, GdkEventMotion *event) { - unsigned char cb, cx, cy; - char buf[LINE_MAX]; - gint len; - int width = terminal->char_width; - int height = terminal->char_height; - long col = ((long) event->x - terminal->pvt->inner_border.left) / width; - long row = ((long) event->y - terminal->pvt->inner_border.top) / height; + int width = terminal->pvt->char_width; + int height = terminal->pvt->char_height; + long col = ((long) event->x - terminal->pvt->padding.left) / width; + long row = ((long) event->y - terminal->pvt->padding.top) / height; /* First determine if we even want to send notification. */ switch (event->type) { case GDK_MOTION_NOTIFY: if (terminal->pvt->mouse_tracking_mode < MOUSE_TRACKING_CELL_MOTION_TRACKING) - return; + return FALSE; if (terminal->pvt->mouse_tracking_mode < MOUSE_TRACKING_ALL_MOTION_TRACKING) { if (terminal->pvt->mouse_last_button == 0) { - return; + return FALSE; } /* the xterm doc is not clear as to whether * all-tracking also sends degenerate same-cell events */ if (col == terminal->pvt->mouse_last_x / width && row == terminal->pvt->mouse_last_y / height) - return; + return FALSE; } break; default: - return; + return FALSE; break; } - vte_terminal_get_mouse_tracking_info (terminal, - terminal->pvt->mouse_last_button, col, row, - &cb, &cx, &cy); - cb += 32; /* for movement */ - - /* Send event direct to the child, this is binary not text data */ - len = g_snprintf(buf, sizeof(buf), _VTE_CAP_CSI "M%c%c%c", cb, cx, cy); - vte_terminal_feed_child_binary(terminal, buf, len); + vte_terminal_feed_mouse_event(terminal, terminal->pvt->mouse_last_button, + TRUE /* drag */, FALSE /* not release */, + col, row); + return TRUE; } /* Clear all match hilites. */ @@ -5998,8 +5689,8 @@ vte_terminal_match_hilite_clear(VteTerminal *terminal) static gboolean cursor_inside_match (VteTerminal *terminal, long x, long y) { - gint width = terminal->char_width; - gint height = terminal->char_height; + gint width = terminal->pvt->char_width; + gint height = terminal->pvt->char_height; glong col = x / width; glong row = y / height + terminal->pvt->screen->scroll_delta; if (terminal->pvt->match_start.row == terminal->pvt->match_end.row) { @@ -6060,8 +5751,8 @@ vte_terminal_match_hilite_update(VteTerminal *terminal, long x, long y) VteScreen *screen; long delta; - width = terminal->char_width; - height = terminal->char_height; + width = terminal->pvt->char_width; + height = terminal->pvt->char_height; /* Check for matches. */ screen = terminal->pvt->screen; @@ -6151,8 +5842,8 @@ vte_terminal_match_hilite(VteTerminal *terminal, long x, long y) int width, height; GtkAllocation allocation; - width = terminal->char_width; - height = terminal->char_height; + width = terminal->pvt->char_width; + height = terminal->pvt->char_height; gtk_widget_get_allocation (&terminal->widget, &allocation); @@ -6243,12 +5934,29 @@ vte_terminal_copy_cb(GtkClipboard *clipboard, GtkSelectionData *data, } } +/* Convert the internal color code (either index or RGB, see vte-private.h) into RGB. */ +static void +vte_terminal_get_rgb_from_index(const VteTerminal *terminal, guint index, PangoColor *color) +{ + if (index >= VTE_LEGACY_COLORS_OFFSET && index < VTE_LEGACY_COLORS_OFFSET + VTE_LEGACY_FULL_COLOR_SET_SIZE) + index -= VTE_LEGACY_COLORS_OFFSET; + if (index < VTE_PALETTE_SIZE) { + memcpy(color, _vte_terminal_get_color(terminal, index), sizeof(PangoColor)); + } else if (index & VTE_RGB_COLOR) { + color->red = ((index >> 16) & 0xFF) * 257; + color->green = ((index >> 8) & 0xFF) * 257; + color->blue = (index & 0xFF) * 257; + } else { + g_assert_not_reached(); + } +} + /** * VteSelectionFunc: * @terminal: terminal in which the cell is. * @column: column in which the cell is. * @row: row in which the cell is. - * @data: user data. + * @data: (closure): user data. * * Specifies the type of a selection function used to check whether * a cell has to be selected or not. @@ -6263,9 +5971,9 @@ vte_terminal_copy_cb(GtkClipboard *clipboard, GtkSelectionData *data, * @start_col: first column to search for data * @end_row: last row to search for data * @end_col: last column to search for data - * @is_selected: a #VteSelectionFunc callback + * @is_selected: (scope call) (allow-none): a #VteSelectionFunc callback * @user_data: (closure): user data to be passed to the callback - * @attributes: (out) (transfer full) (array) (element-type Vte.CharAttributes): location for storing text attributes + * @attributes: (out caller-allocates) (transfer full) (array) (element-type Vte.CharAttributes): location for storing text attributes * * Extracts a view of the visible part of the terminal. If @is_selected is not * %NULL, characters will only be read if @is_selected returns %TRUE after being @@ -6307,24 +6015,20 @@ vte_terminal_get_text_range_maybe_wrapped(VteTerminal *terminal, gboolean include_trailing_spaces) { glong col, row, last_empty, last_emptycol, last_nonempty, last_nonemptycol; - VteScreen *screen; const VteCell *pcell = NULL; GString *string; struct _VteCharAttributes attr; - PangoColor fore, back, *palette; + PangoColor fore, back; if (!is_selected) is_selected = always_selected; - screen = terminal->pvt->screen; - if (attributes) g_array_set_size (attributes, 0); string = g_string_new(NULL); memset(&attr, 0, sizeof(attr)); - palette = terminal->pvt->palette; col = start_col; for (row = start_row; row < end_row + 1; row++, col = 0) { const VteRowData *row_data = _vte_terminal_find_row_data (terminal, row); @@ -6344,8 +6048,8 @@ vte_terminal_get_text_range_maybe_wrapped(VteTerminal *terminal, * the selection. */ if (!pcell->attr.fragment && is_selected(terminal, col, row, data)) { /* Store the attributes of this character. */ - fore = palette[pcell->attr.fore]; - back = palette[pcell->attr.back]; + vte_terminal_get_rgb_from_index(terminal, pcell->attr.fore, &fore); + vte_terminal_get_rgb_from_index(terminal, pcell->attr.back, &back); attr.fore.red = fore.red; attr.fore.green = fore.green; attr.fore.blue = fore.blue; @@ -6410,7 +6114,7 @@ vte_terminal_get_text_range_maybe_wrapped(VteTerminal *terminal, } /* Adjust column, in case we want to append a newline */ - attr.column = MAX(terminal->column_count, attr.column + 1); + attr.column = MAX(terminal->pvt->column_count, attr.column + 1); /* Add a newline in block mode. */ if (terminal->pvt->selection_block_mode) { @@ -6418,7 +6122,7 @@ vte_terminal_get_text_range_maybe_wrapped(VteTerminal *terminal, } /* Else, if the last visible column on this line was selected and * not soft-wrapped, append a newline. */ - else if (is_selected(terminal, terminal->column_count, row, data)) { + else if (is_selected(terminal, terminal->pvt->column_count, row, data)) { /* If we didn't softwrap, add a newline. */ /* XXX need to clear row->soft_wrap on deletion! */ if (!vte_line_is_wrappable(terminal, row)) { @@ -6447,8 +6151,8 @@ vte_terminal_get_text_maybe_wrapped(VteTerminal *terminal, long start_row, start_col, end_row, end_col; start_row = terminal->pvt->screen->scroll_delta; start_col = 0; - end_row = start_row + terminal->row_count - 1; - end_col = terminal->column_count - 1; + end_row = start_row + terminal->pvt->row_count - 1; + end_col = terminal->pvt->column_count - 1; return vte_terminal_get_text_range_maybe_wrapped(terminal, start_row, start_col, end_row, end_col, @@ -6462,9 +6166,9 @@ vte_terminal_get_text_maybe_wrapped(VteTerminal *terminal, /** * vte_terminal_get_text: * @terminal: a #VteTerminal - * @is_selected: a #VteSelectionFunc callback + * @is_selected: (scope call) (allow-none): a #VteSelectionFunc callback * @user_data: (closure): user data to be passed to the callback - * @attributes: (out) (transfer full) (array) (element-type Vte.CharAttributes): location for storing text attributes + * @attributes: (out caller-allocates) (transfer full) (array) (element-type Vte.CharAttributes): location for storing text attributes * * Extracts a view of the visible part of the terminal. If @is_selected is not * %NULL, characters will only be read if @is_selected returns %TRUE after being @@ -6492,9 +6196,9 @@ vte_terminal_get_text(VteTerminal *terminal, /** * vte_terminal_get_text_include_trailing_spaces: * @terminal: a #VteTerminal - * @is_selected: a #VteSelectionFunc callback + * @is_selected: (scope call) (allow-none): a #VteSelectionFunc callback * @user_data: (closure): user data to be passed to the callback - * @attributes: (out) (transfer full) (array) (element-type Vte.CharAttributes): location for storing text attributes + * @attributes: (out caller-allocates) (transfer full) (array) (element-type Vte.CharAttributes): location for storing text attributes * * Extracts a view of the visible part of the terminal. If @is_selected is not * %NULL, characters will only be read if @is_selected returns %TRUE after being @@ -6523,116 +6227,6 @@ vte_terminal_get_text_include_trailing_spaces(VteTerminal *terminal, TRUE); } -static inline void -swap (guint *a, guint *b) -{ - guint tmp; - tmp = *a, *a = *b, *b = tmp; -} - -static void -vte_terminal_determine_colors_internal(VteTerminal *terminal, - const VteCellAttr *attr, - gboolean selected, - gboolean cursor, - guint *pfore, guint *pback) -{ - guint fore, back; - - g_assert(attr); - - /* Start with cell colors */ - fore = attr->fore; - back = attr->back; - - /* Reverse-mode switches default fore and back colors */ - if (G_UNLIKELY (terminal->pvt->screen->reverse_mode)) { - if (fore == VTE_DEF_FG) - fore = VTE_DEF_BG; - if (back == VTE_DEF_BG) - back = VTE_DEF_FG; - } - - /* Handle bold by using set bold color or brightening */ - if (attr->bold) { - if (fore == VTE_DEF_FG) - fore = VTE_BOLD_FG; - else if (fore < VTE_LEGACY_COLOR_SET_SIZE) { - fore += VTE_COLOR_BRIGHT_OFFSET; - } - } - - /* Handle half similarly */ - if (attr->half) { - if (fore == VTE_DEF_FG) - fore = VTE_DIM_FG; - else if ((fore < VTE_LEGACY_COLOR_SET_SIZE)) - fore = corresponding_dim_index[fore]; - } - - /* And standout */ - if (attr->standout) { - if (back < VTE_LEGACY_COLOR_SET_SIZE) - back += VTE_COLOR_BRIGHT_OFFSET; - } - - /* Reverse cell? */ - if (attr->reverse) { - swap (&fore, &back); - } - - /* Selection: use hightlight back, or inverse */ - if (selected) { - /* XXX what if hightlight back is same color as current back? */ - if (terminal->pvt->highlight_color_set) - back = VTE_DEF_HL; - else - swap (&fore, &back); - } - - /* Cursor: use cursor back, or inverse */ - if (cursor) { - /* XXX what if cursor back is same color as current back? */ - if (terminal->pvt->cursor_color_set) - back = VTE_CUR_BG; - else - swap (&fore, &back); - } - - /* Invisible? */ - if (attr->invisible) { - fore = back; - } - - *pfore = fore; - *pback = back; -} - -static inline void -vte_terminal_determine_colors (VteTerminal *terminal, - const VteCell *cell, - gboolean highlight, - guint *fore, guint *back) -{ - return vte_terminal_determine_colors_internal (terminal, - cell ? &cell->attr : &basic_cell.cell.attr, - highlight, FALSE, - fore, back); -} - -static inline void -vte_terminal_determine_cursor_colors (VteTerminal *terminal, - const VteCell *cell, - gboolean highlight, - guint *fore, guint *back) -{ - return vte_terminal_determine_colors_internal (terminal, - cell ? &cell->attr : &basic_cell.cell.attr, - highlight, TRUE, - fore, back); -} - - /* * Compares the visual attributes of a VteCellAttr for equality, but ignores * attributes that tend to change from character to character or are otherwise @@ -6674,24 +6268,28 @@ vte_terminal_cellattr_to_html(VteTerminal *terminal, const VteCellAttr *attr, co g_string_prepend(string, "<b>"); g_string_append(string, "</b>"); } - if (attr->fore != VTE_DEF_FG || attr->reverse) { - PangoColor *color = &terminal->pvt->palette[fore]; - gchar *tag = g_strdup_printf( - "<font color=\"#%02X%02X%02X\">", - color->red >> 8, - color->green >> 8, - color->blue >> 8); + if (attr->fore != VTE_DEFAULT_FG || attr->reverse) { + PangoColor color; + char *tag; + + vte_terminal_get_rgb_from_index(terminal, attr->fore, &color); + tag = g_strdup_printf("<font color=\"#%02X%02X%02X\">", + color.red >> 8, + color.green >> 8, + color.blue >> 8); g_string_prepend(string, tag); g_free(tag); g_string_append(string, "</font>"); } - if (attr->back != VTE_DEF_BG || attr->reverse) { - PangoColor *color = &terminal->pvt->palette[back]; - gchar *tag = g_strdup_printf( - "<span style=\"background-color:#%02X%02X%02X\">", - color->red >> 8, - color->green >> 8, - color->blue >> 8); + if (attr->back != VTE_DEFAULT_BG || attr->reverse) { + PangoColor color; + char *tag; + + vte_terminal_get_rgb_from_index(terminal, attr->back, &color); + tag = g_strdup_printf("<span style=\"background-color:#%02X%02X%02X\">", + color.red >> 8, + color.green >> 8, + color.blue >> 8); g_string_prepend(string, tag); g_free(tag); g_string_append(string, "</span>"); @@ -6791,7 +6389,7 @@ vte_terminal_attributes_to_html(VteTerminal *terminal, const gchar *text, GArray * vte_terminal_get_cursor_position: * @terminal: a #VteTerminal * @column: (out) (allow-none): a location to store the column, or %NULL - * @row : (out) (allow-none): a location to store the row, or %NULL + * @row: (out) (allow-none): a location to store the row, or %NULL * * Reads the location of the insertion cursor and returns it. The row * coordinate is absolute. @@ -6831,7 +6429,7 @@ vte_terminal_copy(VteTerminal *terminal, VteSelection sel) terminal->pvt->selection_start.row, 0, terminal->pvt->selection_end.row, - terminal->column_count, + terminal->pvt->column_count, vte_cell_is_selected, NULL, attributes); @@ -6871,14 +6469,6 @@ vte_terminal_copy(VteTerminal *terminal, VteSelection sel) } } -/* Place the selected text onto the CLIPBOARD clipboard. Do this - * asynchronously, so that we can suppor the html target as well */ -static void -vte_terminal_real_copy_clipboard(VteTerminal *terminal) -{ - vte_terminal_copy(terminal, VTE_SELECTION_CLIPBOARD); -} - /* Paste from the given clipboard. */ static void vte_terminal_paste(VteTerminal *terminal, GdkAtom board) @@ -6905,10 +6495,35 @@ vte_terminal_invalidate_selection (VteTerminal *terminal) terminal->pvt->selection_block_mode); } +/* Confine coordinates into the visible area. Padding is alreday subtracted. */ +static void +vte_terminal_confine_coordinates (VteTerminal *terminal, long *xp, long *yp) +{ + long x = *xp; + long y = *yp; + + if (y < 0) { + y = 0; + if (!terminal->pvt->selection_block_mode) + x = 0; + } else if (y >= terminal->pvt->row_count * terminal->pvt->char_height) { + y = terminal->pvt->row_count * terminal->pvt->char_height - 1; + if (!terminal->pvt->selection_block_mode) + x = terminal->pvt->column_count * terminal->pvt->char_width - 1; + } + if (x < 0) { + x = 0; + } else if (x >= terminal->pvt->column_count * terminal->pvt->char_width) { + x = terminal->pvt->column_count * terminal->pvt->char_width - 1; + } + + *xp = x; + *yp = y; +} /* Start selection at the location of the event. */ static void -vte_terminal_start_selection(VteTerminal *terminal, GdkEventButton *event, +vte_terminal_start_selection(VteTerminal *terminal, long x, long y, enum vte_selection_type selection_type) { long delta; @@ -6918,12 +6533,14 @@ vte_terminal_start_selection(VteTerminal *terminal, GdkEventButton *event, if (terminal->pvt->selection_block_mode) selection_type = selection_type_char; + /* Confine coordinates into the visible area. (#563024, #722635c7) */ + vte_terminal_confine_coordinates(terminal, &x, &y); + /* Record that we have the selection, and where it started. */ delta = terminal->pvt->screen->scroll_delta; terminal->pvt->has_selection = TRUE; - terminal->pvt->selection_last.x = event->x - terminal->pvt->inner_border.left; - terminal->pvt->selection_last.y = event->y - terminal->pvt->inner_border.top + - (terminal->char_height * delta); + terminal->pvt->selection_last.x = x; + terminal->pvt->selection_last.y = y + (terminal->pvt->char_height * delta); /* Decide whether or not to restart on the next drag. */ switch (selection_type) { @@ -6947,6 +6564,7 @@ vte_terminal_start_selection(VteTerminal *terminal, GdkEventButton *event, /* Record the selection type. */ terminal->pvt->selection_type = selection_type; terminal->pvt->selecting = TRUE; + terminal->pvt->selecting_after_threshold = FALSE; _vte_debug_print(VTE_DEBUG_SELECTION, "Selection started at (%ld,%ld).\n", @@ -6975,7 +6593,11 @@ _vte_terminal_maybe_end_selection (VteTerminal *terminal) return TRUE; } - return FALSE; + + if (terminal->pvt->selecting_after_threshold) + return TRUE; + + return FALSE; } static long @@ -7046,17 +6668,18 @@ vte_terminal_extend_selection_expand (VteTerminal *terminal) break; } /* If the end point is to its right, then extend the - * endpoint as far right as we can expect. */ + * endpoint to the beginning of the next row. */ if (ec->col >= i) { - ec->col = MAX(ec->col, - MAX(terminal->column_count, - (long) _vte_row_data_length (rowdata))); + ec->col = -1; + ec->row++; } } else { - /* Snap to the rightmost column, only if selecting anything of - * this row. */ - if (ec->col >= 0) - ec->col = MAX(ec->col, terminal->column_count); + /* Snap to the beginning of the next line, only if + * selecting anything of this row. */ + if (ec->col >= 0) { + ec->col = -1; + ec->row++; + } } ec->col = find_end_column (terminal, ec->col, ec->row); @@ -7080,7 +6703,7 @@ vte_terminal_extend_selection_expand (VteTerminal *terminal) /* Back up. */ for (i = (j == sc->row) ? sc->col : - terminal->column_count; + terminal->pvt->column_count; i > 0; i--) { if (vte_same_class(terminal, @@ -7100,13 +6723,13 @@ vte_terminal_extend_selection_expand (VteTerminal *terminal) } else { if (vte_line_is_wrappable(terminal, j - 1) && vte_same_class(terminal, - terminal->column_count - 1, + terminal->pvt->column_count - 1, j - 1, 0, j)) { /* Move on to the previous line. */ j--; - sc->col = terminal->column_count - 1; + sc->col = terminal->pvt->column_count - 1; sc->row = j; } else { break; @@ -7127,7 +6750,7 @@ vte_terminal_extend_selection_expand (VteTerminal *terminal) for (i = (j == ec->row) ? ec->col : 0; - i < terminal->column_count - 1; + i < terminal->pvt->column_count - 1; i++) { if (vte_same_class(terminal, i, @@ -7140,13 +6763,13 @@ vte_terminal_extend_selection_expand (VteTerminal *terminal) break; } } - if (i < terminal->column_count - 1) { + if (i < terminal->pvt->column_count - 1) { /* We hit a stopping point, so stop. */ break; } else { if (vte_line_is_wrappable(terminal, j) && vte_same_class(terminal, - terminal->column_count - 1, + terminal->pvt->column_count - 1, j, 0, j + 1)) { @@ -7177,14 +6800,10 @@ vte_terminal_extend_selection_expand (VteTerminal *terminal) j++; ec->row = j; } - /* Make sure we include all of the last line. */ - ec->col = terminal->column_count; - if (_vte_ring_contains (screen->row_data, ec->row)) { - rowdata = _vte_ring_index(screen->row_data, ec->row); - if (rowdata != NULL) { - ec->col = MAX(ec->col, (long) _vte_row_data_length (rowdata)); - } - } + /* Make sure we include all of the last line by extending + * to the beginning of the next line. */ + ec->row++; + ec->col = -1; break; } } @@ -7202,22 +6821,11 @@ vte_terminal_extend_selection(VteTerminal *terminal, long x, long y, gboolean invalidate_selected = FALSE; gboolean had_selection; - height = terminal->char_height; - width = terminal->char_width; + height = terminal->pvt->char_height; + width = terminal->pvt->char_width; - /* Confine y into the visible area. (#563024) */ - if (y < 0) { - y = 0; - if (!terminal->pvt->selection_block_mode) - x = 0; - } else if (y >= terminal->row_count * height) { - if (!terminal->pvt->selection_block_mode) { - y = terminal->row_count * height; - x = -1; - } else { - y = terminal->row_count * height - 1; - } - } + /* Confine coordinates into the visible area. (#563024, #722635c7) */ + vte_terminal_confine_coordinates(terminal, &x, &y); screen = terminal->pvt->screen; old_start = terminal->pvt->selection_start; @@ -7464,15 +7072,13 @@ vte_terminal_select_all (VteTerminal *terminal) } /** - * vte_terminal_select_none: + * vte_terminal_unselect_all: * @terminal: a #VteTerminal * * Clears the current selection. - * - * Since: 0.16 */ void -vte_terminal_select_none (VteTerminal *terminal) +vte_terminal_unselect_all(VteTerminal *terminal) { g_return_if_fail (VTE_IS_TERMINAL (terminal)); @@ -7481,8 +7087,6 @@ vte_terminal_select_none (VteTerminal *terminal) vte_terminal_deselect_all (terminal); } - - /* Autoscroll a bit. */ static gboolean vte_terminal_autoscroll(VteTerminal *terminal) @@ -7493,7 +7097,7 @@ vte_terminal_autoscroll(VteTerminal *terminal) /* Provide an immediate effect for mouse wigglers. */ if (terminal->pvt->mouse_last_y < 0) { - if (terminal->adjustment) { + if (terminal->pvt->vadjustment) { /* Try to scroll up by one line. */ adj = terminal->pvt->screen->scroll_delta - 1; vte_terminal_queue_adjustment_value_changed_clamped (terminal, adj); @@ -7502,8 +7106,8 @@ vte_terminal_autoscroll(VteTerminal *terminal) _vte_debug_print(VTE_DEBUG_EVENTS, "Autoscrolling down.\n"); } if (terminal->pvt->mouse_last_y >= - terminal->row_count * terminal->char_height) { - if (terminal->adjustment) { + terminal->pvt->row_count * terminal->pvt->char_height) { + if (terminal->pvt->vadjustment) { /* Try to scroll up by one line. */ adj = terminal->pvt->screen->scroll_delta + 1; vte_terminal_queue_adjustment_value_changed_clamped (terminal, adj); @@ -7513,8 +7117,8 @@ vte_terminal_autoscroll(VteTerminal *terminal) } if (extend) { /* Don't select off-screen areas. That just confuses people. */ - xmax = terminal->column_count * terminal->char_width; - ymax = terminal->row_count * terminal->char_height; + xmax = terminal->pvt->column_count * terminal->pvt->char_width; + ymax = terminal->pvt->row_count * terminal->pvt->char_height; x = CLAMP(terminal->pvt->mouse_last_x, 0, xmax); y = CLAMP(terminal->pvt->mouse_last_y, 0, ymax); @@ -7524,7 +7128,7 @@ vte_terminal_autoscroll(VteTerminal *terminal) x = 0; } if (terminal->pvt->mouse_last_y >= ymax && !terminal->pvt->selection_block_mode) { - x = terminal->column_count * terminal->char_width; + x = terminal->pvt->column_count * terminal->pvt->char_width; } /* Extend selection to cover the newly-scrolled area. */ vte_terminal_extend_selection(terminal, x, y, FALSE, TRUE); @@ -7542,7 +7146,7 @@ vte_terminal_start_autoscroll(VteTerminal *terminal) if (terminal->pvt->mouse_autoscroll_tag == 0) { terminal->pvt->mouse_autoscroll_tag = g_timeout_add_full(G_PRIORITY_LOW, - 666 / terminal->row_count, + 666 / terminal->pvt->row_count, (GSourceFunc)vte_terminal_autoscroll, terminal, NULL); @@ -7563,21 +7167,19 @@ vte_terminal_stop_autoscroll(VteTerminal *terminal) static gboolean vte_terminal_motion_notify(GtkWidget *widget, GdkEventMotion *event) { - VteTerminal *terminal; + VteTerminal *terminal = VTE_TERMINAL(widget); int width, height; long x, y; gboolean handled = FALSE; /* check to see if it matters */ - if (! gtk_widget_is_drawable (widget)) { - return handled; - } + if (G_UNLIKELY(!gtk_widget_get_realized(&terminal->widget))) + return FALSE; - terminal = VTE_TERMINAL(widget); - x = event->x - terminal->pvt->inner_border.left; - y = event->y - terminal->pvt->inner_border.top; - width = terminal->char_width; - height = terminal->char_height; + x = event->x - terminal->pvt->padding.left; + y = event->y - terminal->pvt->padding.top; + width = terminal->pvt->char_width; + height = terminal->pvt->char_height; _vte_debug_print(VTE_DEBUG_EVENTS, "Motion notify (%ld,%ld) [%ld, %ld].\n", @@ -7597,6 +7199,19 @@ vte_terminal_motion_notify(GtkWidget *widget, GdkEventMotion *event) switch (event->type) { case GDK_MOTION_NOTIFY: + if (terminal->pvt->selecting_after_threshold) { + if (!gtk_drag_check_threshold (widget, + terminal->pvt->mouse_last_x, + terminal->pvt->mouse_last_y, + x, y)) + return TRUE; + + vte_terminal_start_selection(terminal, + terminal->pvt->mouse_last_x, + terminal->pvt->mouse_last_y, + selection_type_char); + } + if (terminal->pvt->selecting && ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || !terminal->pvt->mouse_tracking_mode)) @@ -7606,9 +7221,9 @@ vte_terminal_motion_notify(GtkWidget *widget, GdkEventMotion *event) x, y, FALSE, FALSE); /* Start scrolling if we need to. */ - if (event->y < terminal->pvt->inner_border.top || - event->y >= terminal->row_count * height + - terminal->pvt->inner_border.top) + if (event->y < terminal->pvt->padding.top || + event->y >= terminal->pvt->row_count * height + + terminal->pvt->padding.top) { /* Give mouse wigglers something. */ vte_terminal_autoscroll(terminal); @@ -7647,11 +7262,11 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event) terminal = VTE_TERMINAL(widget); - x = event->x - terminal->pvt->inner_border.left; - y = event->y - terminal->pvt->inner_border.top; + x = event->x - terminal->pvt->padding.left; + y = event->y - terminal->pvt->padding.top; - height = terminal->char_height; - width = terminal->char_width; + height = terminal->pvt->char_height; + width = terminal->pvt->char_width; delta = terminal->pvt->screen->scroll_delta; vte_terminal_match_hilite(terminal, x, y); @@ -7669,7 +7284,7 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event) _vte_debug_print(VTE_DEBUG_EVENTS, "Button %d single-click at (%ld,%ld)\n", event->button, - x, y + terminal->char_height * delta); + x, y + terminal->pvt->char_height * delta); /* Handle this event ourselves. */ switch (event->button) { case 1: @@ -7703,9 +7318,7 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event) } if (start_selecting) { vte_terminal_deselect_all(terminal); - vte_terminal_start_selection(terminal, - event, - selection_type_char); + terminal->pvt->selecting_after_threshold = TRUE; handled = TRUE; } if (extend_selecting) { @@ -7724,8 +7337,14 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event) case 2: if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || !terminal->pvt->mouse_tracking_mode) { - vte_terminal_paste_primary(terminal); - handled = TRUE; + gboolean do_paste; + + g_object_get (gtk_widget_get_settings(widget), + "gtk-enable-primary-paste", + &do_paste, NULL); + if (do_paste) + vte_terminal_paste_primary(terminal); + handled = do_paste; } break; case 3: @@ -7735,24 +7354,30 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event) /* If we haven't done anything yet, try sending the mouse * event to the app. */ if (handled == FALSE) { - vte_terminal_maybe_send_mouse_button(terminal, event); - handled = TRUE; + handled = vte_terminal_maybe_send_mouse_button(terminal, event); } break; case GDK_2BUTTON_PRESS: _vte_debug_print(VTE_DEBUG_EVENTS, "Button %d double-click at (%ld,%ld)\n", event->button, - x, y + (terminal->char_height * delta)); + x, y + (terminal->pvt->char_height * delta)); switch (event->button) { case 1: + if (terminal->pvt->selecting_after_threshold) { + vte_terminal_start_selection(terminal, + x, y, + selection_type_char); + handled = TRUE; + } if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || !terminal->pvt->mouse_tracking_mode) { vte_terminal_start_selection(terminal, - event, + x, y, selection_type_word); vte_terminal_extend_selection(terminal, x, y, FALSE, TRUE); + handled = TRUE; } break; case 2: @@ -7765,16 +7390,17 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event) _vte_debug_print(VTE_DEBUG_EVENTS, "Button %d triple-click at (%ld,%ld).\n", event->button, - x, y + (terminal->char_height * delta)); + x, y + (terminal->pvt->char_height * delta)); switch (event->button) { case 1: if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || !terminal->pvt->mouse_tracking_mode) { vte_terminal_start_selection(terminal, - event, + x, y, selection_type_line); vte_terminal_extend_selection(terminal, x, y, FALSE, TRUE); + handled = TRUE; } break; case 2: @@ -7791,7 +7417,7 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event) terminal->pvt->mouse_last_x = x; terminal->pvt->mouse_last_y = y; - return TRUE; + return handled; } /* Read and handle a pointing device buttonrelease event. */ @@ -7804,8 +7430,8 @@ vte_terminal_button_release(GtkWidget *widget, GdkEventButton *event) terminal = VTE_TERMINAL(widget); - x = event->x - terminal->pvt->inner_border.left; - y = event->y - terminal->pvt->inner_border.top; + x = event->x - terminal->pvt->padding.left; + y = event->y - terminal->pvt->padding.top; vte_terminal_match_hilite(terminal, x, y); @@ -7822,25 +7448,17 @@ vte_terminal_button_release(GtkWidget *widget, GdkEventButton *event) event->button, x, y); switch (event->button) { case 1: - /* If Shift is held down, or we're not in events mode, - * copy the selected text. */ - if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || - !terminal->pvt->mouse_tracking_mode) - handled = _vte_terminal_maybe_end_selection (terminal); + handled = _vte_terminal_maybe_end_selection (terminal); break; case 2: - if ((terminal->pvt->modifiers & GDK_SHIFT_MASK) || - !terminal->pvt->mouse_tracking_mode) { - handled = TRUE; - } + handled = TRUE; break; case 3: default: break; } if (!handled) { - vte_terminal_maybe_send_mouse_button(terminal, event); - handled = TRUE; + handled = vte_terminal_maybe_send_mouse_button(terminal, event); } break; default: @@ -7851,8 +7469,9 @@ vte_terminal_button_release(GtkWidget *widget, GdkEventButton *event) terminal->pvt->mouse_last_button = 0; terminal->pvt->mouse_last_x = x; terminal->pvt->mouse_last_y = y; + terminal->pvt->selecting_after_threshold = FALSE; - return TRUE; + return handled; } /* Handle receiving or losing focus. */ @@ -7927,8 +7546,8 @@ vte_terminal_enter(GtkWidget *widget, GdkEventCrossing *event) VteTerminal *terminal = VTE_TERMINAL (widget); /* Hilite any matches. */ vte_terminal_match_hilite_show(terminal, - event->x - terminal->pvt->inner_border.left, - event->y - terminal->pvt->inner_border.top); + event->x - terminal->pvt->padding.left, + event->y - terminal->pvt->padding.top); } return ret; } @@ -8029,21 +7648,21 @@ vte_terminal_apply_metrics(VteTerminal *terminal, descent = MAX(descent, 1); /* Change settings, and keep track of when we've changed anything. */ - if (width != terminal->char_width) { + if (width != terminal->pvt->char_width) { resize = cresize = TRUE; - terminal->char_width = width; + terminal->pvt->char_width = width; } - if (height != terminal->char_height) { + if (height != terminal->pvt->char_height) { resize = cresize = TRUE; - terminal->char_height = height; + terminal->pvt->char_height = height; } - if (ascent != terminal->char_ascent) { + if (ascent != terminal->pvt->char_ascent) { resize = TRUE; - terminal->char_ascent = ascent; + terminal->pvt->char_ascent = ascent; } - if (descent != terminal->char_descent) { + if (descent != terminal->pvt->char_descent) { resize = TRUE; - terminal->char_descent = descent; + terminal->pvt->char_descent = descent; } terminal->pvt->line_thickness = line_thickness = MAX (MIN ((height - ascent) / 2, height / 14), 1); terminal->pvt->underline_position = MIN (ascent + line_thickness, height - line_thickness); @@ -8058,8 +7677,8 @@ vte_terminal_apply_metrics(VteTerminal *terminal, /* Emit a signal that the font changed. */ if (cresize) { vte_terminal_emit_char_size_changed(terminal, - terminal->char_width, - terminal->char_height); + terminal->pvt->char_width, + terminal->pvt->char_height); } /* Repaint. */ _vte_invalidate_all(terminal); @@ -8072,16 +7691,15 @@ vte_terminal_ensure_font (VteTerminal *terminal) if (terminal->pvt->draw != NULL) { /* Load default fonts, if no fonts have been loaded. */ if (!terminal->pvt->has_fonts) { - vte_terminal_set_font_full_internal(terminal, - terminal->pvt->fontdesc, - terminal->pvt->fontantialias); + vte_terminal_set_font(terminal, + terminal->pvt->fontdesc); } if (terminal->pvt->fontdirty) { gint width, height, ascent; terminal->pvt->fontdirty = FALSE; _vte_draw_set_text_font (terminal->pvt->draw, - terminal->pvt->fontdesc, - terminal->pvt->fontantialias); + &terminal->widget, + terminal->pvt->fontdesc); _vte_draw_get_text_metrics (terminal->pvt->draw, &width, &height, &ascent); vte_terminal_apply_metrics(terminal, @@ -8090,40 +7708,59 @@ vte_terminal_ensure_font (VteTerminal *terminal) } } +static void +vte_terminal_update_font(VteTerminal *terminal) +{ + VteTerminalPrivate *pvt = terminal->pvt; + PangoFontDescription *desc; + gdouble size; + + /* We'll get called again later */ + if (pvt->unscaled_font_desc == NULL) + return; -/** - * vte_terminal_set_font_full: + desc = pango_font_description_copy(pvt->unscaled_font_desc); + + size = pango_font_description_get_size(desc); + if (pango_font_description_get_size_is_absolute(desc)) { + pango_font_description_set_absolute_size(desc, pvt->font_scale * size); + } else { + pango_font_description_set_size(desc, pvt->font_scale * size); + } + + if (pvt->fontdesc) { + pango_font_description_free(pvt->fontdesc); + } + pvt->fontdesc = desc; + + pvt->fontdirty = TRUE; + pvt->has_fonts = TRUE; + + /* Set the drawing font. */ + if (gtk_widget_get_realized (&terminal->widget)) { + vte_terminal_ensure_font (terminal); + } +} + +/* + * _vte_terminal_set_font: * @terminal: a #VteTerminal - * @font_desc: The #PangoFontDescription of the desired font, or %NULL - * @antialias: Specify if anti aliasing of the fonts is to be used or not. + * @font_desc: (allow-none): a #PangoFontDescription for the desired font, or %NULL * * 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. - * - * Since: 0.11.11 - * - * Deprecated: 0.20: Use vte_terminal_set_font() */ void -vte_terminal_set_font_full(VteTerminal *terminal, - const PangoFontDescription *font_desc, - VteTerminalAntiAlias antialias) -{ - vte_terminal_set_font_full_internal(terminal, font_desc, antialias); -} - -static void -vte_terminal_set_font_full_internal(VteTerminal *terminal, - const PangoFontDescription *font_desc, - VteTerminalAntiAlias antialias) +vte_terminal_set_font(VteTerminal *terminal, + const PangoFontDescription *font_desc) { GObject *object; - GtkStyle *style; + GtkStyleContext *context; VteTerminalPrivate *pvt; - PangoFontDescription *desc; + PangoFontDescription *desc; gboolean same_desc; g_return_if_fail(VTE_IS_TERMINAL(terminal)); @@ -8132,9 +7769,8 @@ vte_terminal_set_font_full_internal(VteTerminal *terminal, pvt = terminal->pvt; /* Create an owned font description. */ - gtk_widget_ensure_style (&terminal->widget); - style = gtk_widget_get_style (&terminal->widget); - desc = pango_font_description_copy (style->font_desc); + context = gtk_widget_get_style_context(&terminal->widget); + gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL, "font", &desc, NULL); pango_font_description_set_family_static (desc, "monospace"); if (font_desc != NULL) { pango_font_description_merge (desc, font_desc, TRUE); @@ -8151,122 +7787,81 @@ vte_terminal_set_font_full_internal(VteTerminal *terminal, "Using default monospace font.\n"); } - same_desc = pvt->fontdesc && pango_font_description_equal (pvt->fontdesc, desc); - + same_desc = pvt->unscaled_font_desc && + pango_font_description_equal (pvt->unscaled_font_desc, desc); + /* Note that we proceed to recreating the font even if the description - * and antialias settings are the same. This is because maybe screen + * are the same. This is because maybe screen * font options were changed, or new fonts installed. Those will be * detected at font creation time and respected. */ - g_object_freeze_notify(object); - /* Free the old font description and save the new one. */ - if (terminal->pvt->fontdesc != NULL) { - pango_font_description_free(terminal->pvt->fontdesc); + if (terminal->pvt->unscaled_font_desc != NULL) { + pango_font_description_free(terminal->pvt->unscaled_font_desc); } - pvt->fontdesc = desc; - pvt->fontantialias = antialias; - pvt->fontdirty = TRUE; - pvt->has_fonts = TRUE; - if (!same_desc) - g_object_notify(object, "font-desc"); + terminal->pvt->unscaled_font_desc = desc /* adopted */; - /* Set the drawing font. */ - if (gtk_widget_get_realized (&terminal->widget)) { - vte_terminal_ensure_font (terminal); - } + vte_terminal_update_font(terminal); - g_object_thaw_notify(object); + if (!same_desc) + g_object_notify(object, "font-desc"); } -/** - * vte_terminal_set_font: + /** + * vte_terminal_get_font: * @terminal: a #VteTerminal - * @font_desc: (allow-none): a #PangoFontDescription for the desired font, or %NULL * - * 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. + * Queries the terminal for information about the fonts which will be + * used to draw text in the terminal. + * + * Returns: (transfer none): a #PangoFontDescription describing the font the terminal is + * currently using to render text */ -void -vte_terminal_set_font(VteTerminal *terminal, - const PangoFontDescription *font_desc) -{ - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - vte_terminal_set_font_full_internal(terminal, font_desc, - VTE_ANTI_ALIAS_USE_DEFAULT); -} - -static void -vte_terminal_set_font_from_string_full_internal(VteTerminal *terminal, - const char *name, - VteTerminalAntiAlias antialias) +const PangoFontDescription * +vte_terminal_get_font(VteTerminal *terminal) { - PangoFontDescription *font_desc = NULL; - g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); - if (name) - font_desc = pango_font_description_from_string(name); - vte_terminal_set_font_full_internal(terminal, font_desc, antialias); - pango_font_description_free(font_desc); + return terminal->pvt->unscaled_font_desc; } /** - * vte_terminal_set_font_from_string_full: + * vte_terminal_set_font_scale: * @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_full(). + * @scale: the font scale * - * Since: 0.11.11 + * Sets the terminal's font scale to @scale. * - * Deprecated: 0.20: Use vte_terminal_set_font() + * Since: 0.30 */ void -vte_terminal_set_font_from_string_full(VteTerminal *terminal, const char *name, - VteTerminalAntiAlias antialias) +vte_terminal_set_font_scale(VteTerminal *terminal, + gdouble scale) { - vte_terminal_set_font_from_string_full_internal(terminal, name, antialias); -} + g_return_if_fail(VTE_IS_TERMINAL(terminal)); -/** - * vte_terminal_set_font_from_string: - * @terminal: a #VteTerminal - * @name: (type utf8): a pango font description in string form - * - * 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) -{ - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(name != NULL); - vte_terminal_set_font_from_string_full_internal(terminal, name, - VTE_ANTI_ALIAS_USE_DEFAULT); + terminal->pvt->font_scale = CLAMP(scale, VTE_FONT_SCALE_MIN, VTE_FONT_SCALE_MAX); + vte_terminal_update_font(terminal); + + g_object_notify(G_OBJECT(terminal), "font-scale"); } /** - * vte_terminal_get_font: + * vte_terminal_get_font_scale: * @terminal: a #VteTerminal * - * Queries the terminal for information about the fonts which will be - * used to draw text in the terminal. + * Returns: the terminal's font scale * - * Returns: (transfer none): a #PangoFontDescription describing the font the terminal is - * currently using to render text + * Since: 0.30 */ -const PangoFontDescription * -vte_terminal_get_font(VteTerminal *terminal) +gdouble +vte_terminal_get_font_scale(VteTerminal *terminal) { - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); - return terminal->pvt->fontdesc; + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), 1.); + + return terminal->pvt->font_scale; } /* Read and refresh our perception of the size of the PTY. */ @@ -8281,14 +7876,149 @@ vte_terminal_refresh_size(VteTerminal *terminal) return; if (vte_pty_get_size(pvt->pty, &rows, &columns, &error)) { - terminal->row_count = rows; - terminal->column_count = columns; + terminal->pvt->row_count = rows; + terminal->pvt->column_count = columns; } else { g_warning(_("Error reading PTY size, using defaults: %s\n"), error->message); g_error_free(error); } } +/* Resize the given screen (normal or alternate) of the terminal. */ +static void +vte_terminal_screen_set_size(VteTerminal *terminal, VteScreen *screen, glong old_columns, glong old_rows, gboolean do_rewrap) +{ + VteRing *ring = screen->row_data; + VteVisualPosition cursor_saved_absolute; + VteVisualPosition below_viewport; + VteVisualPosition below_current_paragraph; + VteVisualPosition *markers[7]; + gboolean was_scrolled_to_top = (screen->scroll_delta == _vte_ring_delta(ring)); + gboolean was_scrolled_to_bottom = (screen->scroll_delta == screen->insert_delta); + glong old_top_lines; + glong new_scroll_delta; + + _vte_debug_print(VTE_DEBUG_RESIZE, + "Resizing %s screen\n" + "Old insert_delta=%ld scroll_delta=%ld\n" + " cursor_current (absolute) row=%ld (visual line %ld) col=%ld\n" + " cursor_saved (relative to insert_delta) row=%ld col=%ld\n", + screen == &terminal->pvt->normal_screen ? "normal" : "alternate", + screen->insert_delta, screen->scroll_delta, + screen->cursor_current.row, screen->cursor_current.row - screen->scroll_delta + 1, screen->cursor_current.col, + screen->cursor_saved.row, screen->cursor_saved.col); + + screen->scrolling_restricted = FALSE; + + cursor_saved_absolute.row = screen->cursor_saved.row + screen->insert_delta; + cursor_saved_absolute.col = screen->cursor_saved.col; + below_viewport.row = screen->scroll_delta + old_rows; + below_viewport.col = 0; + below_current_paragraph.row = screen->cursor_current.row + 1; + while (below_current_paragraph.row < _vte_ring_next(ring) + && _vte_ring_index(ring, below_current_paragraph.row - 1)->attr.soft_wrapped) { + below_current_paragraph.row++; + } + below_current_paragraph.col = 0; + markers[0] = &screen->cursor_current; + markers[1] = &cursor_saved_absolute; + markers[2] = &below_viewport; + markers[3] = &below_current_paragraph; + if (screen == terminal->pvt->screen && terminal->pvt->has_selection) { + /* selection_end is inclusive, make it non-inclusive, see bug 722635. */ + terminal->pvt->selection_end.col++; + markers[4] = &terminal->pvt->selection_start; + markers[5] = &terminal->pvt->selection_end; + markers[6] = NULL; + } else { + markers[4] = NULL; + } + + old_top_lines = below_current_paragraph.row - screen->insert_delta; + + if (do_rewrap && old_columns != terminal->pvt->column_count) + _vte_ring_rewrap(ring, terminal->pvt->column_count, markers); + + if (_vte_ring_length(ring) > terminal->pvt->row_count) { + /* The content won't fit without scrollbars. Before figuring out the position, we might need to + drop some lines from the ring if the cursor is not at the bottom, as XTerm does. See bug 708213. + This code is really tricky, see ../doc/rewrap.txt for details! */ + glong new_top_lines, drop1, drop2, drop3, drop; + screen->insert_delta = _vte_ring_next(ring) - terminal->pvt->row_count; + new_top_lines = below_current_paragraph.row - screen->insert_delta; + drop1 = _vte_ring_length(ring) - terminal->pvt->row_count; + drop2 = _vte_ring_length(ring) - below_current_paragraph.row; + drop3 = old_top_lines - new_top_lines; + drop = MIN(MIN(drop1, drop2), drop3); + if (drop > 0) { + int new_ring_next = screen->insert_delta + terminal->pvt->row_count - drop; + _vte_debug_print(VTE_DEBUG_RESIZE, + "Dropping %ld [== MIN(%ld, %ld, %ld)] rows at the bottom\n", + drop, drop1, drop2, drop3); + _vte_ring_shrink(ring, new_ring_next - _vte_ring_delta(ring)); + } + } + + if (screen == terminal->pvt->screen && terminal->pvt->has_selection) { + /* Make selection_end inclusive again, see above. */ + terminal->pvt->selection_end.col--; + } + + /* Figure out new insert and scroll deltas */ + if (_vte_ring_length(ring) <= terminal->pvt->row_count) { + /* Everything fits without scrollbars. Align at top. */ + screen->insert_delta = _vte_ring_delta(ring); + new_scroll_delta = screen->insert_delta; + _vte_debug_print(VTE_DEBUG_RESIZE, + "Everything fits without scrollbars\n"); + } else { + /* Scrollbar required. Can't afford unused lines at bottom. */ + screen->insert_delta = _vte_ring_next(ring) - terminal->pvt->row_count; + if (was_scrolled_to_bottom) { + /* Was scrolled to bottom, keep this way. */ + new_scroll_delta = screen->insert_delta; + _vte_debug_print(VTE_DEBUG_RESIZE, + "Scroll to bottom\n"); + } else if (was_scrolled_to_top) { + /* Was scrolled to top, keep this way. Not sure if this special case is worth it. */ + new_scroll_delta = _vte_ring_delta(ring); + _vte_debug_print(VTE_DEBUG_RESIZE, + "Scroll to top\n"); + } else { + /* Try to scroll so that the bottom visible row stays. + More precisely, the character below the bottom left corner stays in that + (invisible) row. + So if the bottom of the screen was at a hard line break then that hard + line break will stay there. + TODO: What would be the best behavior if the bottom of the screen is a + soft line break, i.e. only a partial line is visible at the bottom? */ + new_scroll_delta = below_viewport.row - terminal->pvt->row_count; + _vte_debug_print(VTE_DEBUG_RESIZE, + "Scroll so bottom row stays\n"); + } + } + + /* Don't clamp, they'll be clamped when restored. Until then remember off-screen values + since they might become on-screen again on subsequent resizes. */ + screen->cursor_saved.row = cursor_saved_absolute.row - screen->insert_delta; + screen->cursor_saved.col = cursor_saved_absolute.col; + + _vte_debug_print(VTE_DEBUG_RESIZE, + "New insert_delta=%ld scroll_delta=%ld\n" + " cursor_current (absolute) row=%ld (visual line %ld) col=%ld\n" + " cursor_saved (relative to insert_delta) row=%ld col=%ld\n\n", + screen->insert_delta, new_scroll_delta, + screen->cursor_current.row, screen->cursor_current.row - new_scroll_delta + 1, screen->cursor_current.col, + screen->cursor_saved.row, screen->cursor_saved.col); + + if (screen == terminal->pvt->screen) + vte_terminal_queue_adjustment_value_changed ( + terminal, + new_scroll_delta); + else + screen->scroll_delta = new_scroll_delta; +} + /** * vte_terminal_set_size: * @terminal: a #VteTerminal @@ -8305,12 +8035,12 @@ vte_terminal_set_size(VteTerminal *terminal, glong columns, glong rows) g_return_if_fail(VTE_IS_TERMINAL(terminal)); - _vte_debug_print(VTE_DEBUG_MISC, + _vte_debug_print(VTE_DEBUG_RESIZE, "Setting PTY size to %ldx%ld.\n", columns, rows); - old_rows = terminal->row_count; - old_columns = terminal->column_count; + old_rows = terminal->pvt->row_count; + old_columns = terminal->pvt->column_count; if (terminal->pvt->pty != NULL) { GError *error = NULL; @@ -8324,19 +8054,20 @@ vte_terminal_set_size(VteTerminal *terminal, glong columns, glong rows) } vte_terminal_refresh_size(terminal); } else { - terminal->row_count = rows; - terminal->column_count = columns; + terminal->pvt->row_count = rows; + terminal->pvt->column_count = columns; } - if (old_rows != terminal->row_count || old_columns != terminal->column_count) { - VteScreen *screen = terminal->pvt->screen; - glong visible_rows = MIN (old_rows, _vte_ring_length (screen->row_data)); - if (terminal->row_count < visible_rows) { - glong delta = visible_rows - terminal->row_count; - screen->insert_delta += delta; - vte_terminal_queue_adjustment_value_changed ( - terminal, - screen->scroll_delta + delta); - } + if (old_rows != terminal->pvt->row_count || old_columns != terminal->pvt->column_count) { + _vte_ring_set_visible_rows_hint(terminal->pvt->normal_screen.row_data, terminal->pvt->row_count); + _vte_ring_set_visible_rows_hint(terminal->pvt->alternate_screen.row_data, terminal->pvt->row_count); + + /* Always resize normal screen (given that this feature is enabled), even if alternate is visible: bug 415277 */ + vte_terminal_screen_set_size(terminal, &terminal->pvt->normal_screen, old_columns, old_rows, terminal->pvt->rewrap_on_resize); + /* Resize the alternate screen if it's the current one, but never rewrap it: bug 336238 comment 60 */ + if (terminal->pvt->screen == &terminal->pvt->alternate_screen) + vte_terminal_screen_set_size(terminal, &terminal->pvt->alternate_screen, old_columns, old_rows, FALSE); + + _vte_terminal_adjust_adjustments_full (terminal); gtk_widget_queue_resize_no_redraw (&terminal->widget); /* Our visible text changed. */ vte_terminal_emit_text_modified(terminal); @@ -8353,13 +8084,14 @@ vte_terminal_handle_scroll(VteTerminal *terminal) screen = terminal->pvt->screen; /* Read the new adjustment value and save the difference. */ - adj = round (gtk_adjustment_get_value(terminal->adjustment)); + adj = round (gtk_adjustment_get_value(terminal->pvt->vadjustment)); dy = adj - screen->scroll_delta; screen->scroll_delta = adj; /* Sanity checks. */ - if (! gtk_widget_is_drawable (&terminal->widget) - || terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) { + if (G_UNLIKELY(!gtk_widget_get_realized(&terminal->widget))) + return; + if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) { return; } @@ -8367,7 +8099,7 @@ vte_terminal_handle_scroll(VteTerminal *terminal) _vte_debug_print(VTE_DEBUG_ADJ, "Scrolling by %ld\n", dy); _vte_terminal_scroll_region(terminal, screen->scroll_delta, - terminal->row_count, -dy); + terminal->pvt->row_count, -dy); vte_terminal_emit_text_scrolled(terminal, dy); _vte_terminal_queue_contents_changed(terminal); } else { @@ -8375,7 +8107,6 @@ vte_terminal_handle_scroll(VteTerminal *terminal) } } -#if GTK_CHECK_VERSION (2, 91, 2) static void vte_terminal_set_hadjustment(VteTerminal *terminal, GtkAdjustment *adjustment) @@ -8390,15 +8121,14 @@ vte_terminal_set_hadjustment(VteTerminal *terminal, pvt->hadjustment = adjustment ? g_object_ref_sink (adjustment) : NULL; } -#endif static void vte_terminal_set_vadjustment(VteTerminal *terminal, GtkAdjustment *adjustment) { - if (adjustment != NULL && adjustment == terminal->adjustment) + if (adjustment != NULL && adjustment == terminal->pvt->vadjustment) return; - if (adjustment == NULL && terminal->adjustment != NULL) + if (adjustment == NULL && terminal->pvt->vadjustment != NULL) return; if (adjustment == NULL) @@ -8409,35 +8139,24 @@ vte_terminal_set_vadjustment(VteTerminal *terminal, /* Add a reference to the new adjustment object. */ g_object_ref_sink(adjustment); /* Get rid of the old adjustment object. */ - if (terminal->adjustment != NULL) { + if (terminal->pvt->vadjustment != NULL) { /* Disconnect our signal handlers from this object. */ - g_signal_handlers_disconnect_by_func(terminal->adjustment, + g_signal_handlers_disconnect_by_func(terminal->pvt->vadjustment, vte_terminal_handle_scroll, terminal); - g_object_unref(terminal->adjustment); + g_object_unref(terminal->pvt->vadjustment); } /* Set the new adjustment object. */ - terminal->adjustment = adjustment; + terminal->pvt->vadjustment = adjustment; /* We care about the offset, not the top or bottom. */ - g_signal_connect_swapped(terminal->adjustment, + g_signal_connect_swapped(terminal->pvt->vadjustment, "value-changed", G_CALLBACK(vte_terminal_handle_scroll), terminal); } -/* Set the adjustment objects used by the terminal widget. */ -#if !GTK_CHECK_VERSION (2, 91, 2) -static void -vte_terminal_set_scroll_adjustments(GtkWidget *widget, - GtkAdjustment *hadjustment G_GNUC_UNUSED, - GtkAdjustment *vadjustment) -{ - vte_terminal_set_vadjustment(VTE_TERMINAL(widget), vadjustment); -} -#endif /* GTK 2.x */ - /** * vte_terminal_set_emulation: * @terminal: a #VteTerminal @@ -8450,26 +8169,24 @@ vte_terminal_set_scroll_adjustments(GtkWidget *widget, void vte_terminal_set_emulation(VteTerminal *terminal, const char *emulation) { - VteTerminalPrivate *pvt; GObject *object; int columns, rows; g_return_if_fail(VTE_IS_TERMINAL(terminal)); object = G_OBJECT(terminal); - pvt = terminal->pvt; g_object_freeze_notify(object); /* Set the emulation type, for reference. */ if (emulation == NULL) { - emulation = vte_terminal_get_default_emulation(terminal); + emulation = vte_get_default_emulation(); } terminal->pvt->emulation = g_intern_string(emulation); _vte_debug_print(VTE_DEBUG_MISC, "Setting emulation to `%s'...\n", emulation); /* Find and read the right termcap file. */ - vte_terminal_set_termcap(terminal, NULL, FALSE); + vte_terminal_set_termcap(terminal); /* Create a table to hold the control sequences. */ if (terminal->pvt->matcher != NULL) { @@ -8519,21 +8236,19 @@ vte_terminal_set_emulation(VteTerminal *terminal, const char *emulation) g_object_thaw_notify(object); } -/* FIXMEchpe deprecate this function, it's wrong */ /** - * vte_terminal_get_default_emulation: - * @terminal: a #VteTerminal + * vte_get_default_emulation: * - * Queries the terminal for its default emulation, which is attempted if the + * Returns the default emulation, which is used in #VteTerminal if the * terminal type passed to vte_terminal_set_emulation() is %NULL. * - * Returns: (transfer none) (type utf8): an interned string containing the name of the default terminal - * type the widget attempts to emulate + * Returns: (transfer none) (type utf8): an interned string containing the name + * of the default terminal type the widget attempts to emulate * - * Since: 0.11.11 + * Since: 0.30 */ const char * -vte_terminal_get_default_emulation(VteTerminal *terminal) +vte_get_default_emulation(void) { return g_intern_static_string(VTE_DEFAULT_EMULATION); } @@ -8573,50 +8288,27 @@ _vte_terminal_inline_error_message(VteTerminal *terminal, const char *format, .. /* Set the path to the termcap file we read, and read it in. */ static void -vte_terminal_set_termcap(VteTerminal *terminal, const char *path, - gboolean reset) +vte_terminal_set_termcap(VteTerminal *terminal) { GObject *object = G_OBJECT(terminal); - struct stat st; - char *wpath; - - if (path == NULL) { - wpath = g_build_filename(TERMCAPDIR, - terminal->pvt->emulation ? - terminal->pvt->emulation : - vte_terminal_get_default_emulation(terminal), - NULL); - if (g_stat(wpath, &st) != 0) { - g_free(wpath); - wpath = g_strdup("/etc/termcap"); - } - path = g_intern_string (wpath); - g_free(wpath); - } else { - path = g_intern_string (path); - } - if (path == terminal->pvt->termcap_path) { - return; - } + const char *emulation; g_object_freeze_notify(object); - terminal->pvt->termcap_path = path; + emulation = terminal->pvt->emulation ? terminal->pvt->emulation + : vte_get_default_emulation(); _vte_debug_print(VTE_DEBUG_MISC, "Loading termcap `%s'...", - terminal->pvt->termcap_path); + emulation); if (terminal->pvt->termcap != NULL) { _vte_termcap_free(terminal->pvt->termcap); } - terminal->pvt->termcap = _vte_termcap_new(terminal->pvt->termcap_path); + terminal->pvt->termcap = _vte_termcap_new(emulation); _vte_debug_print(VTE_DEBUG_MISC, "\n"); if (terminal->pvt->termcap == NULL) { _vte_terminal_inline_error_message(terminal, - "Failed to load terminal capabilities from '%s'", - terminal->pvt->termcap_path); - } - if (reset) { - vte_terminal_set_emulation(terminal, terminal->pvt->emulation); + "Failed to load terminal capabilities for '%s'", + emulation); } g_object_thaw_notify(object); @@ -8635,6 +8327,7 @@ static void vte_terminal_init(VteTerminal *terminal) { VteTerminalPrivate *pvt; + GtkStyleContext *context; GdkDisplay *display; _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_init()\n"); @@ -8650,24 +8343,20 @@ vte_terminal_init(VteTerminal *terminal) gtk_widget_set_redraw_on_allocate (&terminal->widget, FALSE); /* Set an adjustment for the application to use to control scrolling. */ - terminal->adjustment = NULL; -#if GTK_CHECK_VERSION (2, 91, 2) + terminal->pvt->vadjustment = NULL; pvt->hadjustment = NULL; /* GtkScrollable */ pvt->hscroll_policy = GTK_SCROLL_NATURAL; pvt->vscroll_policy = GTK_SCROLL_NATURAL; vte_terminal_set_hadjustment(terminal, NULL); -#endif - vte_terminal_set_vadjustment(terminal, NULL); - /* Set up dummy metrics, value != 0 to avoid division by 0 */ - terminal->char_width = 1; - terminal->char_height = 1; - terminal->char_ascent = 1; - terminal->char_descent = 1; + terminal->pvt->char_width = 1; + terminal->pvt->char_height = 1; + terminal->pvt->char_ascent = 1; + terminal->pvt->char_descent = 1; terminal->pvt->line_thickness = 1; terminal->pvt->underline_position = 1; terminal->pvt->strikethrough_position = 1; @@ -8675,7 +8364,7 @@ vte_terminal_init(VteTerminal *terminal) /* We allocated zeroed memory, just fill in non-zero stuff. */ /* Initialize the screens and histories. */ - _vte_ring_init (pvt->alternate_screen.row_data, terminal->row_count); + _vte_ring_init (pvt->alternate_screen.row_data, terminal->pvt->row_count); pvt->alternate_screen.sendrecv_mode = TRUE; pvt->alternate_screen.status_line_contents = g_string_new(NULL); pvt->screen = &terminal->pvt->alternate_screen; @@ -8688,16 +8377,18 @@ vte_terminal_init(VteTerminal *terminal) _vte_terminal_set_default_attributes(terminal); /* Set up I/O encodings. */ + pvt->iso2022_utf8_ambiguous_width = VTE_ISO2022_DEFAULT_UTF8_AMBIGUOUS_WIDTH; pvt->iso2022 = _vte_iso2022_state_new(pvt->encoding, + pvt->iso2022_utf8_ambiguous_width, &_vte_terminal_codeset_changed_cb, terminal); pvt->incoming = NULL; pvt->pending = g_array_new(FALSE, TRUE, sizeof(gunichar)); pvt->max_input_bytes = VTE_MAX_INPUT_READ; pvt->cursor_blink_tag = 0; - pvt->outgoing = _vte_buffer_new(); + pvt->outgoing = _vte_byte_array_new(); pvt->outgoing_conv = VTE_INVALID_CONV; - pvt->conv_buffer = _vte_buffer_new(); + pvt->conv_buffer = _vte_byte_array_new(); vte_terminal_set_encoding(terminal, NULL); g_assert(terminal->pvt->encoding != NULL); @@ -8718,15 +8409,14 @@ vte_terminal_init(VteTerminal *terminal) pvt->pty_input_source = 0; pvt->pty_output_source = 0; pvt->pty_pid = -1; - pvt->child_exit_status = 0; /* Scrolling options. */ pvt->scroll_on_keystroke = TRUE; + pvt->alternate_screen_scroll = TRUE; pvt->scrollback_lines = -1; /* force update in vte_terminal_set_scrollback_lines */ vte_terminal_set_scrollback_lines(terminal, VTE_SCROLLBACK_INIT); /* Selection info. */ - vte_terminal_set_word_chars(terminal, NULL); display = gtk_widget_get_display(&terminal->widget); pvt->clipboard[VTE_SELECTION_PRIMARY] = gtk_clipboard_get_for_display(display, GDK_SELECTION_PRIMARY); pvt->clipboard[VTE_SELECTION_CLIPBOARD] = gtk_clipboard_get_for_display(display, GDK_SELECTION_CLIPBOARD); @@ -8739,6 +8429,8 @@ vte_terminal_init(VteTerminal *terminal) pvt->bell_margin = 10; pvt->allow_bold = TRUE; pvt->nrc_mode = TRUE; + pvt->deccolm_mode = FALSE; + pvt->rewrap_on_resize = TRUE; vte_terminal_set_default_tabstops(terminal); /* Cursor shape. */ @@ -8752,58 +8444,37 @@ vte_terminal_init(VteTerminal *terminal) pvt->cursor_blink_mode = VTE_CURSOR_BLINK_SYSTEM; /* Matching data. */ - pvt->match_regex_mode = VTE_REGEX_UNDECIDED; pvt->match_regexes = g_array_new(FALSE, TRUE, sizeof(struct vte_match_regex)); + pvt->match_tag = -1; vte_terminal_match_hilite_clear(terminal); - /* Rendering data. Try everything. */ - pvt->draw = _vte_draw_new(&terminal->widget); - - /* The font description. */ - pvt->fontantialias = VTE_ANTI_ALIAS_USE_DEFAULT; - gtk_widget_ensure_style(&terminal->widget); + /* Rendering data */ + pvt->draw = _vte_draw_new(); /* Set up background information. */ - pvt->bg_tint_color.red = 0; - pvt->bg_tint_color.green = 0; - pvt->bg_tint_color.blue = 0; - pvt->bg_saturation = 0.4 * VTE_SATURATION_MAX; - pvt->bg_opacity = 0xffff; + pvt->background_alpha = 1.; + pvt->selection_block_mode = FALSE; + pvt->unscaled_font_desc = pvt->fontdesc = NULL; + pvt->font_scale = 1.; pvt->has_fonts = FALSE; - pvt->root_pixmap_changed_tag = 0; + + pvt->alternate_screen_scroll = TRUE; /* Not all backends generate GdkVisibilityNotify, so mark the * window as unobscured initially. */ pvt->visibility_state = GDK_VISIBILITY_UNOBSCURED; - /* Listen for hierarchy change notifications. */ - g_signal_connect(terminal, "hierarchy-changed", - G_CALLBACK(vte_terminal_hierarchy_changed), - NULL); - - pvt->inner_border = default_inner_border; - -#ifdef VTE_DEBUG - /* In debuggable mode, we always do this. */ - /* gtk_widget_get_accessible(&terminal->widget); */ -#endif - -#if GTK_CHECK_VERSION (2, 99, 0) -{ - GtkStyleContext *context; + pvt->padding = default_padding; context = gtk_widget_get_style_context (&terminal->widget); gtk_style_context_add_provider (context, VTE_TERMINAL_GET_CLASS (terminal)->priv->style_provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); } -#endif -} /* Tell GTK+ how much space we need. */ -#if GTK_CHECK_VERSION (2, 91, 0) static void vte_terminal_get_preferred_width(GtkWidget *widget, int *minimum_width, @@ -8818,20 +8489,20 @@ vte_terminal_get_preferred_width(GtkWidget *widget, vte_terminal_ensure_font (terminal); vte_terminal_refresh_size(terminal); - *minimum_width = terminal->char_width * 1; - *natural_width = terminal->char_width * terminal->column_count; + *minimum_width = terminal->pvt->char_width * 1; + *natural_width = terminal->pvt->char_width * terminal->pvt->column_count; - *minimum_width += terminal->pvt->inner_border.left + - terminal->pvt->inner_border.right; - *natural_width += terminal->pvt->inner_border.left + - terminal->pvt->inner_border.right; + *minimum_width += terminal->pvt->padding.left + + terminal->pvt->padding.right; + *natural_width += terminal->pvt->padding.left + + terminal->pvt->padding.right; _vte_debug_print(VTE_DEBUG_WIDGET_SIZE, "[Terminal %p] minimum_width=%d, natural_width=%d for %ldx%ld cells.\n", terminal, *minimum_width, *natural_width, - terminal->column_count, - terminal->row_count); + terminal->pvt->column_count, + terminal->pvt->row_count); } static void @@ -8848,50 +8519,21 @@ vte_terminal_get_preferred_height(GtkWidget *widget, vte_terminal_ensure_font (terminal); vte_terminal_refresh_size(terminal); - *minimum_height = terminal->char_height * 1; - *natural_height = terminal->char_height * terminal->row_count; + *minimum_height = terminal->pvt->char_height * 1; + *natural_height = terminal->pvt->char_height * terminal->pvt->row_count; - *minimum_height += terminal->pvt->inner_border.left + - terminal->pvt->inner_border.right; - *natural_height += terminal->pvt->inner_border.left + - terminal->pvt->inner_border.right; + *minimum_height += terminal->pvt->padding.left + + terminal->pvt->padding.right; + *natural_height += terminal->pvt->padding.left + + terminal->pvt->padding.right; _vte_debug_print(VTE_DEBUG_WIDGET_SIZE, "[Terminal %p] minimum_height=%d, natural_height=%d for %ldx%ld cells.\n", terminal, *minimum_height, *natural_height, - terminal->column_count, - terminal->row_count); + terminal->pvt->column_count, + terminal->pvt->row_count); } -#else /* GTK+ 2.x */ -static void -vte_terminal_size_request(GtkWidget *widget, GtkRequisition *requisition) -{ - VteTerminal *terminal; - - _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_size_request()\n"); - - terminal = VTE_TERMINAL(widget); - - vte_terminal_ensure_font (terminal); - - vte_terminal_refresh_size(terminal); - requisition->width = terminal->char_width * terminal->column_count; - requisition->height = terminal->char_height * terminal->row_count; - - requisition->width += terminal->pvt->inner_border.left + - terminal->pvt->inner_border.right; - requisition->height += terminal->pvt->inner_border.top + - terminal->pvt->inner_border.bottom; - - _vte_debug_print(VTE_DEBUG_WIDGET_SIZE, - "[Terminal %p] Size request is %dx%d for %ldx%ld cells.\n", - terminal, - requisition->width, requisition->height, - terminal->column_count, - terminal->row_count); -} -#endif /* Accept a given size from GTK+. */ static void @@ -8907,10 +8549,10 @@ vte_terminal_size_allocate(GtkWidget *widget, GtkAllocation *allocation) terminal = VTE_TERMINAL(widget); - width = (allocation->width - (terminal->pvt->inner_border.left + terminal->pvt->inner_border.right)) / - terminal->char_width; - height = (allocation->height - (terminal->pvt->inner_border.top + terminal->pvt->inner_border.bottom)) / - terminal->char_height; + width = (allocation->width - (terminal->pvt->padding.left + terminal->pvt->padding.right)) / + terminal->pvt->char_width; + height = (allocation->height - (terminal->pvt->padding.top + terminal->pvt->padding.bottom)) / + terminal->pvt->char_height; width = MAX(width, 1); height = MAX(height, 1); @@ -8929,8 +8571,8 @@ vte_terminal_size_allocate(GtkWidget *widget, GtkAllocation *allocation) /* Set our allocation to match the structure. */ gtk_widget_set_allocation (widget, allocation); - if (width != terminal->column_count - || height != terminal->row_count + if (width != terminal->pvt->column_count + || height != terminal->pvt->row_count || update_scrollback) { VteScreen *screen = terminal->pvt->screen; @@ -8943,10 +8585,10 @@ vte_terminal_size_allocate(GtkWidget *widget, GtkAllocation *allocation) if (screen->scrolling_restricted) { screen->scrolling_region.start = MIN(screen->scrolling_region.start, - terminal->row_count - 1); + terminal->pvt->row_count - 1); screen->scrolling_region.end = MIN(screen->scrolling_region.end, - terminal->row_count - 1); + terminal->pvt->row_count - 1); } /* Ensure scrollback buffers cover the screen. */ @@ -8976,16 +8618,6 @@ vte_terminal_size_allocate(GtkWidget *widget, GtkAllocation *allocation) } } -/* Queue a background update. */ -static void -root_pixmap_changed_cb(VteBg *bg, VteTerminal *terminal) -{ - _vte_debug_print (VTE_DEBUG_EVENTS, "Root pixmap changed.\n"); - if (terminal->pvt->bg_transparent) { - vte_terminal_queue_background_update(terminal); - } -} - /* The window is being destroyed. */ static void vte_terminal_unrealize(GtkWidget *widget) @@ -8998,22 +8630,13 @@ vte_terminal_unrealize(GtkWidget *widget) terminal = VTE_TERMINAL (widget); window = gtk_widget_get_window (widget); - /* Disconnect from background-change events. */ - if (terminal->pvt->root_pixmap_changed_tag != 0) { - VteBg *bg; - bg = vte_bg_get_for_screen(gtk_widget_get_screen(widget)); - g_signal_handler_disconnect (bg, - terminal->pvt->root_pixmap_changed_tag); - terminal->pvt->root_pixmap_changed_tag = 0; - } - /* Deallocate the cursors. */ terminal->pvt->mouse_cursor_visible = FALSE; - gdk_cursor_unref(terminal->pvt->mouse_default_cursor); + g_object_unref(terminal->pvt->mouse_default_cursor); terminal->pvt->mouse_default_cursor = NULL; - gdk_cursor_unref(terminal->pvt->mouse_mousing_cursor); + g_object_unref(terminal->pvt->mouse_mousing_cursor); terminal->pvt->mouse_mousing_cursor = NULL; - gdk_cursor_unref(terminal->pvt->mouse_inviso_cursor); + g_object_unref(terminal->pvt->mouse_inviso_cursor); terminal->pvt->mouse_inviso_cursor = NULL; vte_terminal_match_hilite_clear(terminal); @@ -9054,12 +8677,6 @@ vte_terminal_unrealize(GtkWidget *widget) /* Remove the GDK window. */ if (window != NULL) { - /* detach style */ - GtkStyle *style; - - style = gtk_widget_get_style (widget); - gtk_style_detach (style); - gdk_window_set_user_data (window, NULL); gtk_widget_set_window (widget, NULL); @@ -9153,7 +8770,7 @@ vte_terminal_finalize(GObject *object) { GtkWidget *widget = GTK_WIDGET (object); VteTerminal *terminal = VTE_TERMINAL (object); - GtkWidget *toplevel; + VteTerminalPrivate *pvt = terminal->pvt; GtkClipboard *clipboard; GtkSettings *settings; VteSelection sel; @@ -9170,14 +8787,13 @@ vte_terminal_finalize(GObject *object) /* The NLS maps. */ _vte_iso2022_state_free(terminal->pvt->iso2022); - /* Free background info. */ - g_free(terminal->pvt->bg_file); - /* Free the font description. */ + if (pvt->unscaled_font_desc != NULL) { + pango_font_description_free(pvt->unscaled_font_desc); + } if (terminal->pvt->fontdesc != NULL) { pango_font_description_free(terminal->pvt->fontdesc); } - terminal->pvt->fontantialias = VTE_ANTI_ALIAS_USE_DEFAULT; /* Free matching data. */ if (terminal->pvt->match_attributes != NULL) { @@ -9203,14 +8819,6 @@ vte_terminal_finalize(GObject *object) if (terminal->pvt->search_attrs) g_array_free (terminal->pvt->search_attrs, TRUE); - /* Disconnect from toplevel window configure events. */ - toplevel = gtk_widget_get_toplevel(&terminal->widget); - if ((toplevel != NULL) && (G_OBJECT(toplevel) != object)) { - g_signal_handlers_disconnect_by_func(toplevel, - vte_terminal_configure_toplevel, - terminal); - } - /* Disconnect from autoscroll requests. */ vte_terminal_stop_autoscroll(terminal); @@ -9237,9 +8845,6 @@ vte_terminal_finalize(GObject *object) g_free(terminal->pvt->selection_html[sel]); } } - if (terminal->pvt->word_chars != NULL) { - g_array_free(terminal->pvt->word_chars, TRUE); - } /* Clear the output histories. */ _vte_ring_fini(terminal->pvt->normal_screen.row_data); @@ -9258,21 +8863,19 @@ vte_terminal_finalize(GObject *object) } /* Stop listening for child-exited signals. */ - if (terminal->pvt->pty_reaper != NULL) { - g_signal_handlers_disconnect_by_func(terminal->pvt->pty_reaper, - vte_terminal_catch_child_exited, - terminal); - g_object_unref(terminal->pvt->pty_reaper); - } + if (terminal->pvt->child_watch_source != 0) { + g_source_remove (terminal->pvt->child_watch_source); + terminal->pvt->child_watch_source = 0; + } /* Stop processing input. */ vte_terminal_stop_processing (terminal); /* Discard any pending data. */ _vte_incoming_chunks_release (terminal->pvt->incoming); - _vte_buffer_free(terminal->pvt->outgoing); + _vte_byte_array_free(terminal->pvt->outgoing); g_array_free(terminal->pvt->pending, TRUE); - _vte_buffer_free(terminal->pvt->conv_buffer); + _vte_byte_array_free(terminal->pvt->conv_buffer); /* Stop the child and stop watching for input from the child. */ if (terminal->pvt->pty_pid != -1) { @@ -9311,14 +8914,18 @@ vte_terminal_finalize(GObject *object) remove_update_timeout (terminal); /* discard title updates */ - g_free(terminal->pvt->window_title_changed); + g_free(terminal->pvt->window_title); + g_free(terminal->pvt->window_title_changed); g_free(terminal->pvt->icon_title_changed); + g_free(terminal->pvt->current_directory_uri_changed); + g_free(terminal->pvt->current_directory_uri); + g_free(terminal->pvt->current_file_uri_changed); + g_free(terminal->pvt->current_file_uri); /* Free public-facing data. */ - g_free(terminal->window_title); - g_free(terminal->icon_title); - if (terminal->adjustment != NULL) { - g_object_unref(terminal->adjustment); + g_free(terminal->pvt->icon_title); + if (terminal->pvt->vadjustment != NULL) { + g_object_unref(terminal->pvt->vadjustment); } settings = gtk_widget_get_settings (widget); @@ -9338,19 +8945,13 @@ vte_terminal_realize(GtkWidget *widget) VteTerminal *terminal; GdkWindowAttr attributes; GtkAllocation allocation; - GdkColor color; - guint attributes_mask = 0, i; + guint attributes_mask = 0; _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_realize()\n"); terminal = VTE_TERMINAL(widget); gtk_widget_get_allocation (widget, &allocation); - /* Create the draw structure if we don't already have one. */ - if (terminal->pvt->draw == NULL) { - terminal->pvt->draw = _vte_draw_new(&terminal->widget); - } - /* Create the stock cursors. */ terminal->pvt->mouse_cursor_visible = TRUE; terminal->pvt->mouse_default_cursor = @@ -9366,13 +8967,14 @@ vte_terminal_realize(GtkWidget *widget) attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); -#if !GTK_CHECK_VERSION (2, 90, 8) - attributes.colormap = gtk_widget_get_colormap (widget); -#endif attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK | GDK_VISIBILITY_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | +#if GTK_CHECK_VERSION (3, 4, 0) + GDK_SMOOTH_SCROLL_MASK | +#endif + GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | @@ -9385,9 +8987,6 @@ vte_terminal_realize(GtkWidget *widget) attributes_mask = GDK_WA_X | GDK_WA_Y | (attributes.visual ? GDK_WA_VISUAL : 0) | -#if !GTK_CHECK_VERSION (2, 90, 8) - (attributes.colormap ? GDK_WA_COLORMAP : 0) | -#endif GDK_WA_CURSOR; window = gdk_window_new (gtk_widget_get_parent_window (widget), @@ -9405,15 +9004,6 @@ vte_terminal_realize(GtkWidget *widget) vte_terminal_set_default_colors(terminal); } - /* Allocate colors. */ - for (i = 0; i < G_N_ELEMENTS(terminal->pvt->palette); i++) { - color.red = terminal->pvt->palette[i].red; - color.green = terminal->pvt->palette[i].green; - color.blue = terminal->pvt->palette[i].blue; - color.pixel = 0; - vte_terminal_set_color_internal(terminal, i, &color); - } - /* Set up input method support. FIXME: do we need to handle the * "retrieve-surrounding" and "delete-surrounding" events? */ if (terminal->pvt->im_context != NULL) { @@ -9441,28 +9031,7 @@ vte_terminal_realize(GtkWidget *widget) terminal->pvt->modifiers = 0; /* Create our invisible cursor. */ -#if GTK_CHECK_VERSION (2, 15, 1) terminal->pvt->mouse_inviso_cursor = gdk_cursor_new_for_display(gtk_widget_get_display(widget), GDK_BLANK_CURSOR); -#else - { - GdkPixmap *bitmap; - GdkColor black = {0,0,0,0}; - - bitmap = gdk_bitmap_create_from_data (window, "\0", 1, 1); - terminal->pvt->mouse_inviso_cursor = gdk_cursor_new_from_pixmap(bitmap, - bitmap, - &black, - &black, - 0, 0); - g_object_unref(bitmap); - } -#endif /* GTK >= 2.15.1 */ - -#if GTK_CHECK_VERSION (2, 20, 0) - gtk_widget_style_attach (widget); -#else - widget->style = gtk_style_attach(widget->style, widget->window); -#endif vte_terminal_ensure_font (terminal); @@ -9470,52 +9039,127 @@ vte_terminal_realize(GtkWidget *widget) vte_terminal_background_update(terminal); } -/* Check if a unicode character is actually a graphic character we draw - * ourselves to handle cases where fonts don't have glyphs for them. */ -static gboolean -vte_unichar_is_local_graphic(vteunistr c) +static inline void +swap (guint *a, guint *b) { - if ((c >= 0x2500) && (c <= 0x257f)) { - return TRUE; + guint tmp; + tmp = *a, *a = *b, *b = tmp; +} + +static void +vte_terminal_determine_colors_internal(VteTerminal *terminal, + const VteCellAttr *attr, + gboolean selected, + gboolean cursor, + guint *pfore, guint *pback) +{ + guint fore, back; + + g_assert(attr); + + /* Start with cell colors */ + fore = attr->fore; + back = attr->back; + + /* Reverse-mode switches default fore and back colors */ + if (G_UNLIKELY (terminal->pvt->screen->reverse_mode)) { + if (fore == VTE_DEFAULT_FG) + fore = VTE_DEFAULT_BG; + if (back == VTE_DEFAULT_BG) + back = VTE_DEFAULT_FG; } - switch (c) { - case 0x00a3: /* british pound */ - case 0x00b0: /* degree */ - case 0x00b1: /* plus/minus */ - case 0x00b7: /* bullet */ - case 0x03c0: /* pi */ - case 0x2190: /* left arrow */ - case 0x2191: /* up arrow */ - case 0x2192: /* right arrow */ - case 0x2193: /* down arrow */ - case 0x2260: /* != */ - case 0x2264: /* <= */ - case 0x2265: /* >= */ - case 0x23ba: /* scanline 1/9 */ - case 0x23bb: /* scanline 3/9 */ - case 0x23bc: /* scanline 7/9 */ - case 0x23bd: /* scanline 9/9 */ - case 0x2409: /* HT symbol */ - case 0x240a: /* LF symbol */ - case 0x240b: /* VT symbol */ - case 0x240c: /* FF symbol */ - case 0x240d: /* CR symbol */ - case 0x2424: /* NL symbol */ - case 0x2592: /* checkerboard */ - case 0x25ae: /* solid rectangle */ - case 0x25c6: /* diamond */ - return TRUE; - break; - default: - break; + + /* Handle bold by using set bold color or brightening */ + if (attr->bold) { + if (fore == VTE_DEFAULT_FG) + fore = VTE_BOLD_FG; + else if (fore >= VTE_LEGACY_COLORS_OFFSET && fore < VTE_LEGACY_COLORS_OFFSET + VTE_LEGACY_COLOR_SET_SIZE) { + fore += VTE_COLOR_BRIGHT_OFFSET; + } } - return FALSE; + + /* Handle half similarly */ + if (attr->half) { + if (fore == VTE_DEFAULT_FG) + fore = VTE_DIM_FG; + else if (fore >= VTE_LEGACY_COLORS_OFFSET && fore < VTE_LEGACY_COLORS_OFFSET + VTE_LEGACY_COLOR_SET_SIZE) + fore = corresponding_dim_index[fore - VTE_LEGACY_COLORS_OFFSET]; + } + + /* And standout */ + if (attr->standout) { + if (back >= VTE_LEGACY_COLORS_OFFSET && back < VTE_LEGACY_COLORS_OFFSET + VTE_LEGACY_COLOR_SET_SIZE) + back += VTE_COLOR_BRIGHT_OFFSET; + } + + /* Reverse cell? */ + if (attr->reverse) { + swap (&fore, &back); + } + + /* Selection: use hightlight back/fore, or inverse */ + if (selected) { + /* XXX what if hightlight back is same color as current back? */ + gboolean do_swap = TRUE; + if (_vte_terminal_get_color(terminal, VTE_HIGHLIGHT_BG) != NULL) { + back = VTE_HIGHLIGHT_BG; + do_swap = FALSE; + } + if (_vte_terminal_get_color(terminal, VTE_HIGHLIGHT_FG) != NULL) { + fore = VTE_HIGHLIGHT_FG; + do_swap = FALSE; + } + if (do_swap) + swap (&fore, &back); + } + + /* Cursor: use cursor back, or inverse */ + if (cursor) { + /* XXX what if cursor back is same color as current back? */ + if (_vte_terminal_get_color(terminal, VTE_CURSOR_BG) != NULL) + back = VTE_CURSOR_BG; + else + swap (&fore, &back); + } + + /* Invisible? */ + if (attr->invisible) { + fore = back; + } + + *pfore = fore; + *pback = back; } + +static inline void +vte_terminal_determine_colors (VteTerminal *terminal, + const VteCell *cell, + gboolean highlight, + guint *fore, guint *back) +{ + vte_terminal_determine_colors_internal (terminal, cell ? &cell->attr : &basic_cell.cell.attr, + highlight, FALSE, + fore, back); +} + +static inline void +vte_terminal_determine_cursor_colors (VteTerminal *terminal, + const VteCell *cell, + gboolean highlight, + guint *fore, guint *back) +{ + vte_terminal_determine_colors_internal (terminal, cell ? &cell->attr : &basic_cell.cell.attr, + highlight, TRUE, + fore, back); +} + +/* Check if a unicode character is actually a graphic character we draw + * ourselves to handle cases where fonts don't have glyphs for them. */ static gboolean -vte_terminal_unichar_is_local_graphic(VteTerminal *terminal, vteunistr c, gboolean bold) +vte_unichar_is_local_graphic(vteunistr c) { - return vte_unichar_is_local_graphic (c) && - !_vte_draw_has_char (terminal->pvt->draw, c, bold); + /* Box Drawing & Block Elements */ + return (c >= 0x2500) && (c <= 0x259f); } static void @@ -9526,13 +9170,11 @@ vte_terminal_fill_rectangle(VteTerminal *terminal, gint width, gint height) { - _vte_draw_start(terminal->pvt->draw); _vte_draw_fill_rectangle(terminal->pvt->draw, - x + terminal->pvt->inner_border.left, - y + terminal->pvt->inner_border.top, + x + terminal->pvt->padding.left, + y + terminal->pvt->padding.top, width, height, color, VTE_DRAW_OPAQUE); - _vte_draw_end(terminal->pvt->draw); } static void @@ -9556,23 +9198,14 @@ vte_terminal_draw_rectangle(VteTerminal *terminal, gint width, gint height) { - _vte_draw_start(terminal->pvt->draw); _vte_draw_draw_rectangle(terminal->pvt->draw, - x + terminal->pvt->inner_border.left, - y + terminal->pvt->inner_border.top, + x + terminal->pvt->padding.left, + y + terminal->pvt->padding.top, width, height, color, VTE_DRAW_OPAQUE); - _vte_draw_end(terminal->pvt->draw); } -static void -vte_terminal_draw_point(VteTerminal *terminal, - const PangoColor *color, - gint x, - gint y) -{ - vte_terminal_fill_rectangle(terminal, color, x, y, 1, 1); -} +#include "box_drawing.h" /* Draw the graphic representation of a line-drawing or special graphics * character. */ @@ -9580,759 +9213,479 @@ static gboolean vte_terminal_draw_graphic(VteTerminal *terminal, vteunistr c, guint fore, guint back, gboolean draw_default_bg, gint x, gint y, - gint column_width, gint columns, gint row_height, - gboolean bold) + gint column_width, gint columns, gint row_height) { - gboolean ret; - gint xcenter, xright, ycenter, ybottom, i; - struct _vte_draw_text_request request; + gint width, xcenter, xright, ycenter, ybottom; + int upper_half, lower_half, left_half, right_half; + int light_line_width, heavy_line_width; + double adjust; + cairo_t *cr = _vte_draw_get_context (terminal->pvt->draw); - request.c = c; - request.x = x + terminal->pvt->inner_border.left; - request.y = y + terminal->pvt->inner_border.top; - request.columns = columns; + PangoColor fg, bg; + vte_terminal_get_rgb_from_index(terminal, fore, &fg); + vte_terminal_get_rgb_from_index(terminal, back, &bg); - xright = x + column_width * columns; - ybottom = y + row_height; - xcenter = (x + xright) / 2; - ycenter = (y + ybottom) / 2; + width = column_width * columns; - if ((back != VTE_DEF_BG) || draw_default_bg) { + if ((back != VTE_DEFAULT_BG) || draw_default_bg) { vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[back], - x, y, - column_width * columns, row_height); + &bg, + x, y, width, row_height); } - if (_vte_draw_char(terminal->pvt->draw, &request, - &terminal->pvt->palette[fore], VTE_DRAW_OPAQUE, bold)) { - /* We were able to draw with actual fonts. */ - return TRUE; - } + cairo_save (cr); - ret = TRUE; - - switch (c) { - case 124: - xcenter--; - ycenter--; - xright--; - ybottom--; - /* != */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2 - 1, ycenter, - (xright + xcenter) / 2 + 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2 - 1, - (ybottom + ycenter) / 2, - (xright + xcenter) / 2 + 1, - (ybottom + ycenter) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, y + 1, - x + 1, ybottom - 1); - break; - case 127: - xcenter--; - ycenter--; - xright--; - ybottom--; - /* A "delete" symbol I saw somewhere. */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, ycenter, - xcenter, y); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, y, - xright - 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, ycenter, - xright - 1, ybottom - 1); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, ybottom - 1, - x, ybottom - 1); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, ybottom - 1, - x, ycenter); - break; - case 0x00a3: - xcenter--; - ycenter--; - xright--; - ybottom--; - /* British pound. An "L" with a hyphen. */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2, - (y + ycenter) / 2, - (x + xcenter) / 2, - (ycenter + ybottom) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2, - (ycenter + ybottom) / 2, - (xcenter + xright) / 2, - (ycenter + ybottom) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, ycenter, - xcenter + 1, ycenter); - break; - case 0x00b0: /* f */ - /* litle circle */ - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter - 1, ycenter); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter + 1, ycenter); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter - 1); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter + 1); - break; - case 0x00b1: /* g */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* +/- */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, - (y + ycenter) / 2, - xcenter, - (ycenter + ybottom) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2, - ycenter, - (xcenter + xright) / 2, - ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2, - (ycenter + ybottom) / 2, - (xcenter + xright) / 2, - (ycenter + ybottom) / 2); - break; - case 0x00b7: - xcenter--; - ycenter--; - xright--; - ybottom--; - /* short hyphen? */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter - 1, ycenter, - xcenter + 1, ycenter); - break; - case 0x3c0: /* pi */ - xcenter--; - ycenter--; - xright--; - ybottom--; - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2 - 1, - (y + ycenter) / 2, - (xright + xcenter) / 2 + 1, - (y + ycenter) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2, - (y + ycenter) / 2, - (x + xcenter) / 2, - (ybottom + ycenter) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (xright + xcenter) / 2, - (y + ycenter) / 2, - (xright + xcenter) / 2, - (ybottom + ycenter) / 2); - break; - /* case 0x2190: FIXME */ - /* case 0x2191: FIXME */ - /* case 0x2192: FIXME */ - /* case 0x2193: FIXME */ - /* case 0x2260: FIXME */ - case 0x2264: /* y */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* <= */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, y, - x, (y + ycenter) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, (y + ycenter) / 2, - xright - 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, ycenter, - xright - 1, (ycenter + ybottom) / 2); - break; - case 0x2265: /* z */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* >= */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - xright - 1, (y + ycenter) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, (y + ycenter) / 2, - x, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, ycenter, - x, (ycenter + ybottom) / 2); - break; - case 0x23ba: /* o */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, y, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x23bb: /* p */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, (y + ycenter) / 2, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x23bc: /* r */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - (ycenter + ybottom) / 2, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x23bd: /* s */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ybottom - 1, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x2409: /* b */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* H */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - x, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, y, - xcenter, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, (y + ycenter) / 2, - xcenter, (y + ycenter) / 2); - /* T */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xright - 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (xcenter + xright) / 2, ycenter, - (xcenter + xright) / 2, ybottom - 1); - break; - case 0x240a: /* e */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* L */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - x, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, ycenter, - xcenter, ycenter); - /* F */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xcenter, ybottom - 1); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xright - 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, (ycenter + ybottom) / 2, - xright - 1, (ycenter + ybottom) / 2); - break; - case 0x240b: /* i */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* V */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - (x + xcenter) / 2, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (x + xcenter) / 2, ycenter, - xcenter, y); - /* T */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xright - 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - (xcenter + xright) / 2, ycenter, - (xcenter + xright) / 2, ybottom - 1); - break; - case 0x240c: /* c */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* F */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - x, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - xcenter, y); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, (y + ycenter) / 2, - xcenter, (y + ycenter) / 2); - /* F */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xcenter, ybottom - 1); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xright - 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, (ycenter + ybottom) / 2, - xright - 1, (ycenter + ybottom) / 2); - break; - case 0x240d: /* d */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* C */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - x, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - xcenter, y); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, ycenter, - xcenter, ycenter); - /* R */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xcenter, ybottom - 1); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xright - 1, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, ycenter, - xright - 1, (ycenter + ybottom) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xright - 1, (ycenter + ybottom) / 2, - xcenter, (ycenter + ybottom) / 2); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, (ycenter + ybottom) / 2, - xright - 1, ybottom - 1); - break; - case 0x2424: /* h */ - xcenter--; - ycenter--; - xright--; - ybottom--; - /* N */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - x, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - x, y, - xcenter, ycenter); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, y, - xcenter, ycenter); - /* L */ - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter, - xcenter, ybottom - 1); - vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], - xcenter, ybottom - 1, - xright - 1, ybottom - 1); - break; - case 0x2500: /* q */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x2501: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - column_width * columns, - VTE_LINE_WIDTH * 2); - break; - case 0x2502: /* x */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH, - row_height); - break; - case 0x2503: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH * 2, - row_height); - break; - case 0x250c: /* l */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - xright - xcenter, - VTE_LINE_WIDTH); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - VTE_LINE_WIDTH, - ybottom - ycenter); - break; - case 0x250f: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - xright - xcenter, - VTE_LINE_WIDTH * 2); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - VTE_LINE_WIDTH * 2, - ybottom - ycenter); - break; - case 0x2510: /* k */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - xcenter - x + VTE_LINE_WIDTH, - VTE_LINE_WIDTH); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - VTE_LINE_WIDTH, - ybottom - ycenter); - break; - case 0x2513: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - xcenter - x + VTE_LINE_WIDTH * 2, - VTE_LINE_WIDTH * 2); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - VTE_LINE_WIDTH * 2, - ybottom - ycenter); - break; - case 0x2514: /* m */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - xright - xcenter, - VTE_LINE_WIDTH); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH, - ycenter - y + VTE_LINE_WIDTH); - break; - case 0x2517: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - xright - xcenter, - VTE_LINE_WIDTH * 2); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH * 2, - ycenter - y + VTE_LINE_WIDTH * 2); - break; - case 0x2518: /* j */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - xcenter - x + VTE_LINE_WIDTH, - VTE_LINE_WIDTH); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH, - ycenter - y + VTE_LINE_WIDTH); - break; - case 0x251b: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - xcenter - x + VTE_LINE_WIDTH * 2, - VTE_LINE_WIDTH * 2); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH * 2, - ycenter - y + VTE_LINE_WIDTH * 2); - break; - case 0x251c: /* t */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH, - row_height); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - xright - xcenter, - VTE_LINE_WIDTH); - break; - case 0x2523: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH * 2, - row_height); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - xright - xcenter, - VTE_LINE_WIDTH * 2); - break; - case 0x2524: /* u */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH, - row_height); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - xcenter - x + VTE_LINE_WIDTH, - VTE_LINE_WIDTH); - break; - case 0x252b: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH * 2, - row_height); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - xcenter - x + VTE_LINE_WIDTH * 2, - VTE_LINE_WIDTH * 2); - break; - case 0x252c: /* w */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - VTE_LINE_WIDTH, - ybottom - ycenter); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x2533: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - ycenter, - VTE_LINE_WIDTH * 2, - ybottom - ycenter); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - column_width * columns, - VTE_LINE_WIDTH * 2); - break; - case 0x2534: /* v */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH, - ycenter - y + VTE_LINE_WIDTH); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x253c: /* n */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH, - row_height); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - column_width * columns, - VTE_LINE_WIDTH); - break; - case 0x254b: - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - xcenter, - y, - VTE_LINE_WIDTH * 2, - row_height); - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, - ycenter, - column_width * columns, - VTE_LINE_WIDTH * 2); - break; - case 0x2592: /* a */ - for (i = x; i < xright + 1; i++) { - gint j, draw = ((i - x) & 1) == 0; - for (j = y; j < ybottom; j++) { - if (draw) { - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - i, j); - } - draw = !draw; - } - } - break; - case 0x25ae: /* solid rectangle */ - vte_terminal_fill_rectangle(terminal, - &terminal->pvt->palette[fore], - x, y, - xright - x, ybottom - y); - break; - case 0x25c6: - /* diamond */ - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter - 2, ycenter); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter + 2, ycenter); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter - 2); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter, ycenter + 2); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter - 1, ycenter - 1); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter - 1, ycenter + 1); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter + 1, ycenter - 1); - vte_terminal_draw_point(terminal, - &terminal->pvt->palette[fore], - xcenter + 1, ycenter + 1); - break; - default: - ret = FALSE; - break; - } - return ret; + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + _vte_draw_set_source_color_alpha (terminal->pvt->draw, &fg, VTE_DRAW_OPAQUE); + + // FIXME wtf!? + x += terminal->pvt->padding.left; + y += terminal->pvt->padding.top; + + upper_half = row_height / 2; + lower_half = row_height - upper_half; + left_half = width / 2; + right_half = width - left_half; + + /* Note that the upper/left halves above are the same as 4 eights */ + /* FIXME: this could be smarter for very small n (< 8 resp. < 4) */ +#define EIGHTS(n, k) \ + ({ int k_eights = (n) * (k) / 8; \ + k_eights = MAX(k_eights, 1); \ + k_eights; \ + }) + + light_line_width = terminal->pvt->char_width / 5; + light_line_width = MAX (light_line_width, 1); + + if (c >= 0x2550 && c <= 0x256c) { + heavy_line_width = 3 * light_line_width; + } else { + heavy_line_width = light_line_width + 2; + } + + xcenter = x + left_half; + ycenter = y + upper_half; + xright = x + width; + ybottom = y + row_height; + + switch (c) { + + /* Box Drawing */ + case 0x2500: /* box drawings light horizontal */ + case 0x2501: /* box drawings heavy horizontal */ + case 0x2502: /* box drawings light vertical */ + case 0x2503: /* box drawings heavy vertical */ + case 0x250c: /* box drawings light down and right */ + case 0x250d: /* box drawings down light and right heavy */ + case 0x250e: /* box drawings down heavy and right light */ + case 0x250f: /* box drawings heavy down and right */ + case 0x2510: /* box drawings light down and left */ + case 0x2511: /* box drawings down light and left heavy */ + case 0x2512: /* box drawings down heavy and left light */ + case 0x2513: /* box drawings heavy down and left */ + case 0x2514: /* box drawings light up and right */ + case 0x2515: /* box drawings up light and right heavy */ + case 0x2516: /* box drawings up heavy and right light */ + case 0x2517: /* box drawings heavy up and right */ + case 0x2518: /* box drawings light up and left */ + case 0x2519: /* box drawings up light and left heavy */ + case 0x251a: /* box drawings up heavy and left light */ + case 0x251b: /* box drawings heavy up and left */ + case 0x251c: /* box drawings light vertical and right */ + case 0x251d: /* box drawings vertical light and right heavy */ + case 0x251e: /* box drawings up heavy and right down light */ + case 0x251f: /* box drawings down heavy and right up light */ + case 0x2520: /* box drawings vertical heavy and right light */ + case 0x2521: /* box drawings down light and right up heavy */ + case 0x2522: /* box drawings up light and right down heavy */ + case 0x2523: /* box drawings heavy vertical and right */ + case 0x2524: /* box drawings light vertical and left */ + case 0x2525: /* box drawings vertical light and left heavy */ + case 0x2526: /* box drawings up heavy and left down light */ + case 0x2527: /* box drawings down heavy and left up light */ + case 0x2528: /* box drawings vertical heavy and left light */ + case 0x2529: /* box drawings down light and left up heavy */ + case 0x252a: /* box drawings up light and left down heavy */ + case 0x252b: /* box drawings heavy vertical and left */ + case 0x252c: /* box drawings light down and horizontal */ + case 0x252d: /* box drawings left heavy and right down light */ + case 0x252e: /* box drawings right heavy and left down light */ + case 0x252f: /* box drawings down light and horizontal heavy */ + case 0x2530: /* box drawings down heavy and horizontal light */ + case 0x2531: /* box drawings right light and left down heavy */ + case 0x2532: /* box drawings left light and right down heavy */ + case 0x2533: /* box drawings heavy down and horizontal */ + case 0x2534: /* box drawings light up and horizontal */ + case 0x2535: /* box drawings left heavy and right up light */ + case 0x2536: /* box drawings right heavy and left up light */ + case 0x2537: /* box drawings up light and horizontal heavy */ + case 0x2538: /* box drawings up heavy and horizontal light */ + case 0x2539: /* box drawings right light and left up heavy */ + case 0x253a: /* box drawings left light and right up heavy */ + case 0x253b: /* box drawings heavy up and horizontal */ + case 0x253c: /* box drawings light vertical and horizontal */ + case 0x253d: /* box drawings left heavy and right vertical light */ + case 0x253e: /* box drawings right heavy and left vertical light */ + case 0x253f: /* box drawings vertical light and horizontal heavy */ + case 0x2540: /* box drawings up heavy and down horizontal light */ + case 0x2541: /* box drawings down heavy and up horizontal light */ + case 0x2542: /* box drawings vertical heavy and horizontal light */ + case 0x2543: /* box drawings left up heavy and right down light */ + case 0x2544: /* box drawings right up heavy and left down light */ + case 0x2545: /* box drawings left down heavy and right up light */ + case 0x2546: /* box drawings right down heavy and left up light */ + case 0x2547: /* box drawings down light and up horizontal heavy */ + case 0x2548: /* box drawings up light and down horizontal heavy */ + case 0x2549: /* box drawings right light and left vertical heavy */ + case 0x254a: /* box drawings left light and right vertical heavy */ + case 0x254b: /* box drawings heavy vertical and horizontal */ + case 0x2550: /* box drawings double horizontal */ + case 0x2551: /* box drawings double vertical */ + case 0x2552: /* box drawings down single and right double */ + case 0x2553: /* box drawings down double and right single */ + case 0x2554: /* box drawings double down and right */ + case 0x2555: /* box drawings down single and left double */ + case 0x2556: /* box drawings down double and left single */ + case 0x2557: /* box drawings double down and left */ + case 0x2558: /* box drawings up single and right double */ + case 0x2559: /* box drawings up double and right single */ + case 0x255a: /* box drawings double up and right */ + case 0x255b: /* box drawings up single and left double */ + case 0x255c: /* box drawings up double and left single */ + case 0x255d: /* box drawings double up and left */ + case 0x255e: /* box drawings vertical single and right double */ + case 0x255f: /* box drawings vertical double and right single */ + case 0x2560: /* box drawings double vertical and right */ + case 0x2561: /* box drawings vertical single and left double */ + case 0x2562: /* box drawings vertical double and left single */ + case 0x2563: /* box drawings double vertical and left */ + case 0x2564: /* box drawings down single and horizontal double */ + case 0x2565: /* box drawings down double and horizontal single */ + case 0x2566: /* box drawings double down and horizontal */ + case 0x2567: /* box drawings up single and horizontal double */ + case 0x2568: /* box drawings up double and horizontal single */ + case 0x2569: /* box drawings double up and horizontal */ + case 0x256a: /* box drawings vertical single and horizontal double */ + case 0x256b: /* box drawings vertical double and horizontal single */ + case 0x256c: /* box drawings double vertical and horizontal */ + case 0x2574: /* box drawings light left */ + case 0x2575: /* box drawings light up */ + case 0x2576: /* box drawings light right */ + case 0x2577: /* box drawings light down */ + case 0x2578: /* box drawings heavy left */ + case 0x2579: /* box drawings heavy up */ + case 0x257a: /* box drawings heavy right */ + case 0x257b: /* box drawings heavy down */ + case 0x257c: /* box drawings light left and heavy right */ + case 0x257d: /* box drawings light up and heavy down */ + case 0x257e: /* box drawings heavy left and light right */ + case 0x257f: /* box drawings heavy up and light down */ + { + guint32 bitmap = _vte_box_drawing_bitmaps[c - 0x2500]; + int xboundaries[6] = { 0, + left_half - heavy_line_width / 2, + left_half - light_line_width / 2, + left_half - light_line_width / 2 + light_line_width, + left_half - heavy_line_width / 2 + heavy_line_width, + terminal->pvt->char_width}; + int yboundaries[6] = { 0, + upper_half - heavy_line_width / 2, + upper_half - light_line_width / 2, + upper_half - light_line_width / 2 + light_line_width, + upper_half - heavy_line_width / 2 + heavy_line_width, + terminal->pvt->char_height}; + int xi, yi; + cairo_set_line_width(cr, 0); + for (yi = 4; yi >= 0; yi--) { + for (xi = 4; xi >= 0; xi--) { + if (bitmap & 1) { + cairo_rectangle(cr, + x + xboundaries[xi], + y + yboundaries[yi], + xboundaries[xi + 1] - xboundaries[xi], + yboundaries[yi + 1] - yboundaries[yi]); + cairo_fill(cr); + } + bitmap >>= 1; + } + } + break; + } + + case 0x2504: /* box drawings light triple dash horizontal */ + case 0x2505: /* box drawings heavy triple dash horizontal */ + case 0x2506: /* box drawings light triple dash vertical */ + case 0x2507: /* box drawings heavy triple dash vertical */ + case 0x2508: /* box drawings light quadruple dash horizontal */ + case 0x2509: /* box drawings heavy quadruple dash horizontal */ + case 0x250a: /* box drawings light quadruple dash vertical */ + case 0x250b: /* box drawings heavy quadruple dash vertical */ + case 0x254c: /* box drawings light double dash horizontal */ + case 0x254d: /* box drawings heavy double dash horizontal */ + case 0x254e: /* box drawings light double dash vertical */ + case 0x254f: /* box drawings heavy double dash vertical */ + { + const guint v = c - 0x2500; + int size, line_width; + + size = (v & 2) ? row_height : width; + + switch (v >> 2) { + case 1: /* triple dash */ + { + double segment = size / 8.; + double dashes[2] = { segment * 2., segment }; + cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.); + break; + } + case 2: /* quadruple dash */ + { + double segment = size / 11.; + double dashes[2] = { segment * 2., segment }; + cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.); + break; + } + case 19: /* double dash */ + { + double segment = size / 5.; + double dashes[2] = { segment * 2., segment }; + cairo_set_dash(cr, dashes, G_N_ELEMENTS(dashes), 0.); + break; + } + } + + line_width = (v & 1) ? heavy_line_width : light_line_width; + adjust = (line_width & 1) ? .5 : 0.; + + cairo_set_line_width(cr, line_width); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + if (v & 2) { + cairo_move_to(cr, xcenter + adjust, y); + cairo_line_to(cr, xcenter + adjust, y + row_height); + } else { + cairo_move_to(cr, x, ycenter + adjust); + cairo_line_to(cr, x + width, ycenter + adjust); + } + cairo_stroke(cr); + break; + } + + case 0x256d: /* box drawings light arc down and right */ + case 0x256e: /* box drawings light arc down and left */ + case 0x256f: /* box drawings light arc up and left */ + case 0x2570: /* box drawings light arc up and right */ + { + const guint v = c - 0x256d; + int line_width; + int radius; + + cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); + + line_width = light_line_width; + adjust = (line_width & 1) ? .5 : 0.; + cairo_set_line_width(cr, line_width); + + radius = (terminal->pvt->char_width + 2) / 3; + radius = MAX(radius, heavy_line_width); + + if (v & 2) { + cairo_move_to(cr, xcenter + adjust, y); + cairo_line_to(cr, xcenter + adjust, ycenter - radius + 2 * adjust); + } else { + cairo_move_to(cr, xcenter + adjust, ybottom); + cairo_line_to(cr, xcenter + adjust, ycenter + radius); + } + cairo_stroke(cr); + + cairo_arc(cr, + (v == 1 || v == 2) ? xcenter - radius + 2 * adjust + : xcenter + radius, + (v & 2) ? ycenter - radius + 2 * adjust + : ycenter + radius, + radius - adjust, + (v + 2) * M_PI / 2.0, (v + 3) * M_PI / 2.0); + cairo_stroke(cr); + + if (v == 1 || v == 2) { + cairo_move_to(cr, xcenter - radius + 2 * adjust, ycenter + adjust); + cairo_line_to(cr, x, ycenter + adjust); + } else { + cairo_move_to(cr, xcenter + radius, ycenter + adjust); + cairo_line_to(cr, xright, ycenter + adjust); + } + + cairo_stroke(cr); + break; + } + + case 0x2571: /* box drawings light diagonal upper right to lower left */ + case 0x2572: /* box drawings light diagonal upper left to lower right */ + case 0x2573: /* box drawings light diagonal cross */ + { + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width(cr, light_line_width); + adjust = light_line_width / 2.; + if (c != 0x2571) { + cairo_move_to(cr, x + adjust, y + adjust); + cairo_line_to(cr, xright - adjust, ybottom - adjust); + cairo_stroke(cr); + } + if (c != 0x2572) { + cairo_move_to(cr, xright - adjust, y + adjust); + cairo_line_to(cr, x + adjust, ybottom - adjust); + cairo_stroke(cr); + } + break; + } + + /* Block Elements */ + case 0x2580: /* upper half block */ + cairo_rectangle(cr, x, y, width, upper_half); + cairo_fill (cr); + break; + + case 0x2581: /* lower one eighth block */ + case 0x2582: /* lower one quarter block */ + case 0x2583: /* lower three eighths block */ + case 0x2584: /* lower half block */ + case 0x2585: /* lower five eighths block */ + case 0x2586: /* lower three quarters block */ + case 0x2587: /* lower seven eighths block */ + { + const guint v = c - 0x2580; + /* Use the number of eights from the top, so that + * U+2584 aligns with U+2596..U+259f. + */ + const int h = EIGHTS (row_height, 8 - v); + + cairo_rectangle(cr, x, y + h, width, row_height - h); + cairo_fill (cr); + break; + } + + case 0x2588: /* full block */ + case 0x2589: /* left seven eighths block */ + case 0x258a: /* left three quarters block */ + case 0x258b: /* left five eighths block */ + case 0x258c: /* left half block */ + case 0x258d: /* left three eighths block */ + case 0x258e: /* left one quarter block */ + case 0x258f: /* left one eighth block */ + { + const guint v = c - 0x2588; + /* Use the number of eights from the top, so that + * U+258c aligns with U+2596..U+259f. + */ + const int w = EIGHTS (width, 8 - v); + + cairo_rectangle(cr, x, y, w, row_height); + cairo_fill (cr); + break; + } + + case 0x2590: /* right half block */ + cairo_rectangle(cr, x + left_half, y, right_half, row_height); + cairo_fill (cr); + break; + + case 0x2591: /* light shade */ + case 0x2592: /* medium shade */ + case 0x2593: /* dark shade */ + cairo_set_source_rgba (cr, + fg.red / 65535., + fg.green / 65535., + fg.blue / 65535., + (c - 0x2590) / 4.); + cairo_rectangle(cr, x, y, width, row_height); + cairo_fill (cr); + break; + + case 0x2594: /* upper one eighth block */ + { + const int h = EIGHTS (row_height, 1); /* Align with U+2587 */ + cairo_rectangle(cr, x, y, width, h); + cairo_fill (cr); + break; + } + + case 0x2595: /* right one eighth block */ + { + const int w = EIGHTS (width, 7); /* Align with U+2589 */ + cairo_rectangle(cr, x + w, y, width - w, row_height); + cairo_fill (cr); + break; + } + + case 0x2596: /* quadrant lower left */ + cairo_rectangle(cr, x, y + upper_half, left_half, lower_half); + cairo_fill (cr); + break; + + case 0x2597: /* quadrant lower right */ + cairo_rectangle(cr, x + left_half, y + upper_half, right_half, lower_half); + cairo_fill (cr); + break; + + case 0x2598: /* quadrant upper left */ + cairo_rectangle(cr, x, y, left_half, upper_half); + cairo_fill (cr); + break; + + case 0x2599: /* quadrant upper left and lower left and lower right */ + cairo_rectangle(cr, x, y, left_half, upper_half); + cairo_rectangle(cr, x, y + upper_half, left_half, lower_half); + cairo_rectangle(cr, x + left_half, y + upper_half, right_half, lower_half); + cairo_fill (cr); + break; + + case 0x259a: /* quadrant upper left and lower right */ + cairo_rectangle(cr, x, y, left_half, upper_half); + cairo_rectangle(cr, x + left_half, y + upper_half, right_half, lower_half); + cairo_fill (cr); + break; + + case 0x259b: /* quadrant upper left and upper right and lower left */ + cairo_rectangle(cr, x, y, left_half, upper_half); + cairo_rectangle(cr, x + left_half, y, right_half, upper_half); + cairo_rectangle(cr, x, y + upper_half, left_half, lower_half); + cairo_fill (cr); + break; + + case 0x259c: /* quadrant upper left and upper right and lower right */ + cairo_rectangle(cr, x, y, left_half, upper_half); + cairo_rectangle(cr, x + left_half, y, right_half, upper_half); + cairo_rectangle(cr, x + left_half, y + upper_half, right_half, lower_half); + cairo_fill (cr); + break; + + case 0x259d: /* quadrant upper right */ + cairo_rectangle(cr, x + left_half, y, right_half, upper_half); + cairo_fill (cr); + break; + + case 0x259e: /* quadrant upper right and lower left */ + cairo_rectangle(cr, x + left_half, y, right_half, upper_half); + cairo_rectangle(cr, x, y + upper_half, left_half, lower_half); + cairo_fill (cr); + break; + + case 0x259f: /* quadrant upper right and lower left and lower right */ + cairo_rectangle(cr, x + left_half, y, right_half, upper_half); + cairo_rectangle(cr, x, y + upper_half, left_half, lower_half); + cairo_rectangle(cr, x + left_half, y + upper_half, right_half, lower_half); + cairo_fill (cr); + break; + + default: + g_assert_not_reached(); + } + +#undef EIGHTS + + cairo_restore(cr); + + return TRUE; } /* Draw a string of characters with similar attributes. */ @@ -10341,13 +9694,13 @@ vte_terminal_draw_cells(VteTerminal *terminal, struct _vte_draw_text_request *items, gssize n, guint fore, guint back, gboolean clear, gboolean draw_default_bg, - gboolean bold, gboolean underline, + gboolean bold, gboolean italic, gboolean underline, gboolean strikethrough, gboolean hilite, gboolean boxed, gint column_width, gint row_height) { - int i, x, y, ascent; + int i, x, y; gint columns = 0; - PangoColor *fg, *bg, *defbg; + PangoColor fg, bg; g_assert(n > 0); _VTE_DEBUG_IF(VTE_DEBUG_CELLS) { @@ -10365,10 +9718,8 @@ vte_terminal_draw_cells(VteTerminal *terminal, } bold = bold && terminal->pvt->allow_bold; - fg = &terminal->pvt->palette[fore]; - bg = &terminal->pvt->palette[back]; - defbg = &terminal->pvt->palette[VTE_DEF_BG]; - ascent = terminal->char_ascent; + vte_terminal_get_rgb_from_index(terminal, fore, &fg); + vte_terminal_get_rgb_from_index(terminal, back, &bg); i = 0; do { @@ -10377,26 +9728,30 @@ vte_terminal_draw_cells(VteTerminal *terminal, y = items[i].y; for (; i < n && items[i].y == y; i++) { /* Adjust for the border. */ - items[i].x += terminal->pvt->inner_border.left; - items[i].y += terminal->pvt->inner_border.top; + items[i].x += terminal->pvt->padding.left; + items[i].y += terminal->pvt->padding.top; columns += items[i].columns; } - if (clear && (draw_default_bg || bg != defbg)) { + if (clear && (draw_default_bg || back != VTE_DEFAULT_BG)) { + gint bold_offset = _vte_draw_has_bold(terminal->pvt->draw, + VTE_DRAW_BOLD) ? 0 : bold; _vte_draw_fill_rectangle(terminal->pvt->draw, - x + terminal->pvt->inner_border.left, - y + terminal->pvt->inner_border.top, - columns * column_width + bold, - row_height, - bg, VTE_DRAW_OPAQUE); + x + terminal->pvt->padding.left, + y + terminal->pvt->padding.top, + columns * column_width + bold_offset, row_height, + &bg, VTE_DRAW_OPAQUE); } } while (i < n); + _vte_draw_text(terminal->pvt->draw, items, n, - fg, VTE_DRAW_OPAQUE, bold); + &fg, VTE_DRAW_OPAQUE, + _vte_draw_get_style(bold, italic)); + for (i = 0; i < n; i++) { /* Deadjust for the border. */ - items[i].x -= terminal->pvt->inner_border.left; - items[i].y -= terminal->pvt->inner_border.top; + items[i].x -= terminal->pvt->padding.left; + items[i].y -= terminal->pvt->padding.top; } /* Draw whatever SFX are required. */ @@ -10410,7 +9765,7 @@ vte_terminal_draw_cells(VteTerminal *terminal, } if (underline) { vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], + &fg, x, y + terminal->pvt->underline_position, x + (columns * column_width) - 1, @@ -10418,7 +9773,7 @@ vte_terminal_draw_cells(VteTerminal *terminal, } if (strikethrough) { vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], + &fg, x, y + terminal->pvt->strikethrough_position, x + (columns * column_width) - 1, @@ -10426,7 +9781,7 @@ vte_terminal_draw_cells(VteTerminal *terminal, } if (hilite) { vte_terminal_draw_line(terminal, - &terminal->pvt->palette[fore], + &fg, x, y + row_height - 1, x + (columns * column_width) - 1, @@ -10434,7 +9789,7 @@ vte_terminal_draw_cells(VteTerminal *terminal, } if (boxed) { vte_terminal_draw_rectangle(terminal, - &terminal->pvt->palette[fore], + &fg, x, y, MAX(0, (columns * column_width)), MAX(0, row_height)); @@ -10443,44 +9798,6 @@ vte_terminal_draw_cells(VteTerminal *terminal, } } -/* Try to map a PangoColor to a palette entry and return its index. */ -static guint -_vte_terminal_map_pango_color(VteTerminal *terminal, PangoColor *color) -{ - long distance[G_N_ELEMENTS(terminal->pvt->palette)]; - guint i, ret; - - /* Calculate a "distance" value. Could stand to be improved a bit. */ - for (i = 0; i < G_N_ELEMENTS(distance); i++) { - const PangoColor *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; - } - } - - _vte_debug_print(VTE_DEBUG_UPDATES, - "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); - - 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 @@ -10569,8 +9886,10 @@ _vte_terminal_apply_pango_attr(VteTerminal *terminal, PangoAttribute *attr, case PANGO_ATTR_FOREGROUND: case PANGO_ATTR_BACKGROUND: attrcolor = (PangoAttrColor*) attr; - ival = _vte_terminal_map_pango_color(terminal, - &attrcolor->color); + ival = VTE_RGB_COLOR | + ((attrcolor->color.red & 0xFF00) << 8) | + ((attrcolor->color.green & 0xFF00)) | + ((attrcolor->color.blue & 0xFF00) >> 8); for (i = attr->start_index; i < attr->end_index && i < n_cells; i++) { @@ -10699,6 +10018,7 @@ vte_terminal_draw_cells_with_attributes(VteTerminal *terminal, back, TRUE, draw_default_bg, cells[j].attr.bold, + cells[j].attr.italic, cells[j].attr.underline, cells[j].attr.strikethrough, FALSE, FALSE, column_width, height); @@ -10722,8 +10042,7 @@ vte_terminal_draw_rows(VteTerminal *terminal, struct _vte_draw_text_request items[4*VTE_DRAW_MAX_LENGTH]; gint i, j, row, rows, x, y, end_column; guint fore, nfore, back, nback; - glong delta; - gboolean underline, nunderline, bold, nbold, hilite, nhilite, + gboolean underline, nunderline, bold, nbold, italic, nitalic, hilite, nhilite, selected, nselected, strikethrough, nstrikethrough; guint item_count; const VteCell *cell; @@ -10734,9 +10053,8 @@ vte_terminal_draw_rows(VteTerminal *terminal, end_column = start_column + column_count; /* clear the background */ - delta = screen->scroll_delta; - x = start_x + terminal->pvt->inner_border.left; - y = start_y + terminal->pvt->inner_border.top; + x = start_x + terminal->pvt->padding.left; + y = start_y + terminal->pvt->padding.top; row = start_row; rows = row_count; do { @@ -10783,14 +10101,18 @@ vte_terminal_draw_rows(VteTerminal *terminal, bold = cell && cell->attr.bold; j += cell ? cell->attr.columns : 1; } - if (back != VTE_DEF_BG) { + if (back != VTE_DEFAULT_BG) { + PangoColor bg; + gint bold_offset = _vte_draw_has_bold(terminal->pvt->draw, + VTE_DRAW_BOLD) ? 0 : bold; + vte_terminal_get_rgb_from_index(terminal, back, &bg); _vte_draw_fill_rectangle ( terminal->pvt->draw, x + i * column_width, y, - (j - i) * column_width + bold, + (j - i) * column_width + bold_offset, row_height, - &terminal->pvt->palette[back], VTE_DRAW_OPAQUE); + &bg, VTE_DRAW_OPAQUE); } /* We'll need to continue at the first cell which didn't * match the first one in this set. */ @@ -10808,13 +10130,15 @@ vte_terminal_draw_rows(VteTerminal *terminal, j++; } vte_terminal_determine_colors(terminal, NULL, selected, &fore, &back); - if (back != VTE_DEF_BG) { + if (back != VTE_DEFAULT_BG) { + PangoColor bg; + vte_terminal_get_rgb_from_index(terminal, back, &bg); _vte_draw_fill_rectangle (terminal->pvt->draw, x + i *column_width, y, (j - i) * column_width, row_height, - &terminal->pvt->palette[back], VTE_DRAW_OPAQUE); + &bg, VTE_DRAW_OPAQUE); } i = j; } while (i < end_column); @@ -10870,6 +10194,7 @@ vte_terminal_draw_rows(VteTerminal *terminal, underline = cell->attr.underline; strikethrough = cell->attr.strikethrough; bold = cell->attr.bold; + italic = cell->attr.italic; if (terminal->pvt->show_match) { hilite = vte_cell_is_between(i, row, terminal->pvt->match_start.col, @@ -10888,7 +10213,7 @@ vte_terminal_draw_rows(VteTerminal *terminal, j = i + items[0].columns; /* If this is a graphics character, draw it locally. */ - if (vte_terminal_unichar_is_local_graphic(terminal, cell->c, cell->attr.bold)) { + if (vte_unichar_is_local_graphic(cell->c)) { if (vte_terminal_draw_graphic(terminal, items[0].c, fore, back, @@ -10897,8 +10222,7 @@ vte_terminal_draw_rows(VteTerminal *terminal, items[0].y, column_width, items[0].columns, - row_height, - cell->attr.bold)) { + row_height)) { i = j; continue; } @@ -10936,22 +10260,10 @@ vte_terminal_draw_rows(VteTerminal *terminal, * in this chunk. */ selected = vte_cell_is_selected(terminal, j, row, NULL); vte_terminal_determine_colors(terminal, cell, selected, &nfore, &nback); - /* Graphic characters must be drawn individually. */ - if (vte_terminal_unichar_is_local_graphic(terminal, cell->c, cell->attr.bold)) { - if (vte_terminal_draw_graphic(terminal, - cell->c, - nfore, nback, - FALSE, - start_x + j * column_width, - y, - column_width, - cell->attr.columns, - row_height, - cell->attr.bold)) { - - j += cell->attr.columns; - continue; - } + /* Graphic characters must be drawn individually and thus break the + * run of characters with the same attributes. */ + if (vte_unichar_is_local_graphic(cell->c)) { + break; } if (nfore != fore) { break; @@ -10960,6 +10272,10 @@ vte_terminal_draw_rows(VteTerminal *terminal, if (nbold != bold) { break; } + nitalic = cell->attr.italic; + if (nitalic != italic) { + break; + } /* Break up underlined/not-underlined text. */ nunderline = cell->attr.underline; if (nunderline != underline) { @@ -11024,7 +10340,7 @@ fg_draw: items, item_count, fore, back, FALSE, FALSE, - bold, underline, + bold, italic, underline, strikethrough, hilite, FALSE, column_width, row_height); item_count = 1; @@ -11044,41 +10360,38 @@ fg_out: } static void -vte_terminal_expand_region (VteTerminal *terminal, GdkRegion *region, const GdkRectangle *area) +vte_terminal_expand_region (VteTerminal *terminal, cairo_region_t *region, const GdkRectangle *area) { - VteScreen *screen; int width, height; int row, col, row_stop, col_stop; - VteRegionRectangle rect; + cairo_rectangle_int_t rect; - screen = terminal->pvt->screen; - - width = terminal->char_width; - height = terminal->char_height; + width = terminal->pvt->char_width; + height = terminal->pvt->char_height; /* increase the paint by one pixel on all sides to force the * inclusion of neighbouring cells */ - row = MAX(0, (area->y - terminal->pvt->inner_border.top - 1) / height); - row_stop = MIN(howmany(area->height + area->y - terminal->pvt->inner_border.top + 1, height), - terminal->row_count); + row = MAX(0, (area->y - terminal->pvt->padding.top - 1) / height); + row_stop = MIN(howmany(area->height + area->y - terminal->pvt->padding.top + 1, height), + terminal->pvt->row_count); if (row_stop <= row) { return; } - col = MAX(0, (area->x - terminal->pvt->inner_border.left - 1) / width); - col_stop = MIN(howmany(area->width + area->x - terminal->pvt->inner_border.left + 1, width), - terminal->column_count); + col = MAX(0, (area->x - terminal->pvt->padding.left - 1) / width); + col_stop = MIN(howmany(area->width + area->x - terminal->pvt->padding.left + 1, width), + terminal->pvt->column_count); if (col_stop <= col) { return; } - rect.x = col*width + terminal->pvt->inner_border.left; + rect.x = col*width + terminal->pvt->padding.left; rect.width = (col_stop - col) * width; - rect.y = row*height + terminal->pvt->inner_border.top; + rect.y = row*height + terminal->pvt->padding.top; rect.height = (row_stop - row)*height; /* the rect must be cell aligned to avoid overlapping XY bands */ - gdk_region_union_with_rect(region, &rect); + cairo_region_union_rectangle(region, &rect); _vte_debug_print (VTE_DEBUG_UPDATES, "vte_terminal_expand_region" @@ -11099,18 +10412,18 @@ vte_terminal_paint_area (VteTerminal *terminal, const GdkRectangle *area) screen = terminal->pvt->screen; - width = terminal->char_width; - height = terminal->char_height; + width = terminal->pvt->char_width; + height = terminal->pvt->char_height; - row = MAX(0, (area->y - terminal->pvt->inner_border.top) / height); - row_stop = MIN((area->height + area->y - terminal->pvt->inner_border.top) / height, - terminal->row_count); + row = MAX(0, (area->y - terminal->pvt->padding.top) / height); + row_stop = MIN((area->height + area->y - terminal->pvt->padding.top) / height, + terminal->pvt->row_count); if (row_stop <= row) { return; } - col = MAX(0, (area->x - terminal->pvt->inner_border.left) / width); - col_stop = MIN((area->width + area->x - terminal->pvt->inner_border.left) / width, - terminal->column_count); + col = MAX(0, (area->x - terminal->pvt->padding.left) / width); + col_stop = MIN((area->width + area->x - terminal->pvt->padding.left) / width, + terminal->pvt->column_count); if (col_stop <= col) { return; } @@ -11121,8 +10434,8 @@ vte_terminal_paint_area (VteTerminal *terminal, const GdkRectangle *area) " [(%d,%d)x(%d,%d) pixels]\n", area->x, area->y, area->width, area->height, col, row, col_stop - col, row_stop - row, - col * width + terminal->pvt->inner_border.left, - row * height + terminal->pvt->inner_border.top, + col * width + terminal->pvt->padding.left, + row * height + terminal->pvt->padding.top, (col_stop - col) * width, (row_stop - row) * height); @@ -11148,6 +10461,7 @@ vte_terminal_paint_cursor(VteTerminal *terminal) int row, drow, col; long width, height, delta, cursor_width; guint fore, back; + PangoColor bg; int x, y; gboolean blink, selected, focus; @@ -11159,11 +10473,11 @@ vte_terminal_paint_cursor(VteTerminal *terminal) col = screen->cursor_current.col; drow = screen->cursor_current.row; row = drow - delta; - width = terminal->char_width; - height = terminal->char_height; + width = terminal->pvt->char_width; + height = terminal->pvt->char_height; - if ((CLAMP(col, 0, terminal->column_count - 1) != col) || - (CLAMP(row, 0, terminal->row_count - 1) != row)) + if ((CLAMP(col, 0, terminal->pvt->column_count - 1) != col) || + (CLAMP(row, 0, terminal->pvt->row_count - 1) != row)) return; focus = terminal->pvt->has_focus; @@ -11181,19 +10495,23 @@ vte_terminal_paint_cursor(VteTerminal *terminal) /* Draw the cursor. */ item.c = (cell && cell->c) ? cell->c : ' '; - item.columns = cell ? cell->attr.columns : 1; + item.columns = item.c == '\t' ? 1 : cell ? cell->attr.columns : 1; item.x = col * width; item.y = row * height; cursor_width = item.columns * width; if (cell && cell->c != 0) { - gint cw = _vte_draw_get_char_width (terminal->pvt->draw, - cell->c, cell->attr.columns, cell->attr.bold); + guint style; + gint cw; + style = _vte_draw_get_style(cell->attr.bold, cell->attr.italic); + cw = _vte_draw_get_char_width (terminal->pvt->draw, cell->c, + cell->attr.columns, style); cursor_width = MAX(cursor_width, cw); } selected = vte_cell_is_selected(terminal, col, drow, NULL); vte_terminal_determine_cursor_colors(terminal, cell, selected, &fore, &back); + vte_terminal_get_rgb_from_index(terminal, back, &bg); x = item.x; y = item.y; @@ -11206,7 +10524,7 @@ vte_terminal_paint_cursor(VteTerminal *terminal) stem_width = (int) (((float) height) * terminal->pvt->cursor_aspect_ratio + 0.5); stem_width = CLAMP (stem_width, VTE_LINE_WIDTH, cursor_width); - vte_terminal_fill_rectangle(terminal, &terminal->pvt->palette[back], + vte_terminal_fill_rectangle(terminal, &bg, x, y, stem_width, height); break; } @@ -11214,10 +10532,12 @@ vte_terminal_paint_cursor(VteTerminal *terminal) case VTE_CURSOR_SHAPE_UNDERLINE: { int line_height; - line_height = (int) (((float) width) * terminal->pvt->cursor_aspect_ratio + 0.5); + /* use height (not width) so underline and ibeam will + * be equally visible */ + line_height = (int) (((float) height) * terminal->pvt->cursor_aspect_ratio + 0.5); line_height = CLAMP (line_height, VTE_LINE_WIDTH, height); - vte_terminal_fill_rectangle(terminal, &terminal->pvt->palette[back], + vte_terminal_fill_rectangle(terminal, &bg, x, y + height - line_height, cursor_width, line_height); break; @@ -11228,11 +10548,11 @@ vte_terminal_paint_cursor(VteTerminal *terminal) if (focus) { /* just reverse the character under the cursor */ vte_terminal_fill_rectangle (terminal, - &terminal->pvt->palette[back], + &bg, x, y, cursor_width, height); - if (!vte_terminal_unichar_is_local_graphic(terminal, item.c, cell ? cell->attr.bold : FALSE) || + if (!vte_unichar_is_local_graphic(item.c) || !vte_terminal_draw_graphic(terminal, item.c, fore, back, @@ -11241,8 +10561,7 @@ vte_terminal_paint_cursor(VteTerminal *terminal) item.y, width, item.columns, - height, - cell ? cell->attr.bold : FALSE)) { + height)) { gboolean hilite = FALSE; if (cell && terminal->pvt->show_match) { hilite = vte_cell_is_between(col, row, @@ -11257,6 +10576,7 @@ vte_terminal_paint_cursor(VteTerminal *terminal) &item, 1, fore, back, TRUE, FALSE, cell->attr.bold, + cell->attr.italic, cell->attr.underline, cell->attr.strikethrough, hilite, @@ -11270,7 +10590,7 @@ vte_terminal_paint_cursor(VteTerminal *terminal) /* draw a box around the character */ vte_terminal_draw_rectangle (terminal, - &terminal->pvt->palette[back], + &bg, x - VTE_LINE_WIDTH, y - VTE_LINE_WIDTH, cursor_width + 2*VTE_LINE_WIDTH, @@ -11285,8 +10605,8 @@ static void vte_terminal_paint_im_preedit_string(VteTerminal *terminal) { VteScreen *screen; - int row, drow, col, columns; - long width, height, ascent, descent, delta; + int row, col, columns; + long width, height, delta; int i, len; guint fore, back; @@ -11297,13 +10617,10 @@ vte_terminal_paint_im_preedit_string(VteTerminal *terminal) screen = terminal->pvt->screen; /* Keep local copies of rendering information. */ - width = terminal->char_width; - height = terminal->char_height; - ascent = terminal->char_ascent; - descent = terminal->char_descent; + width = terminal->pvt->char_width; + height = terminal->pvt->char_height; delta = screen->scroll_delta; - drow = screen->cursor_current.row; row = screen->cursor_current.row - delta; /* Find out how many columns the pre-edit string takes up. */ @@ -11313,8 +10630,8 @@ vte_terminal_paint_im_preedit_string(VteTerminal *terminal) /* If the pre-edit string won't fit on the screen if we start * drawing it at the cursor's position, move it left. */ col = screen->cursor_current.col; - if (col + columns > terminal->column_count) { - col = MAX(0, terminal->column_count - columns); + if (col + columns > terminal->pvt->column_count) { + col = MAX(0, terminal->pvt->column_count - columns); } /* Draw the preedit string, boxed. */ @@ -11334,12 +10651,12 @@ vte_terminal_paint_im_preedit_string(VteTerminal *terminal) preedit = g_utf8_next_char(preedit); } _vte_draw_clear(terminal->pvt->draw, - col * width + terminal->pvt->inner_border.left, - row * height + terminal->pvt->inner_border.top, + col * width + terminal->pvt->padding.left, + row * height + terminal->pvt->padding.top, width * columns, height); - fore = screen->defaults.attr.fore; - back = screen->defaults.attr.back; + fore = screen->color_defaults.attr.fore; + back = screen->color_defaults.attr.back; vte_terminal_draw_cells_with_attributes(terminal, items, len, terminal->pvt->im_preedit_attrs, @@ -11355,6 +10672,7 @@ vte_terminal_paint_im_preedit_string(VteTerminal *terminal) FALSE, FALSE, FALSE, + FALSE, TRUE, width, height); } @@ -11362,66 +10680,64 @@ vte_terminal_paint_im_preedit_string(VteTerminal *terminal) } } -/* Draw the widget. */ -static void -vte_terminal_paint(GtkWidget *widget, GdkRegion *region) +static gboolean +vte_terminal_draw(GtkWidget *widget, + cairo_t *cr) { - VteTerminal *terminal; - GtkAllocation allocation; + VteTerminal *terminal = VTE_TERMINAL (widget); + cairo_rectangle_int_t clip_rect; + cairo_region_t *region; + int allocated_width, allocated_height; - _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_paint()\n"); - _vte_debug_print(VTE_DEBUG_WORK, "="); + if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect)) + return FALSE; - terminal = VTE_TERMINAL(widget); - gtk_widget_get_allocation (widget, &allocation); + _vte_debug_print(VTE_DEBUG_LIFECYCLE, "vte_terminal_draw()\n"); + _vte_debug_print (VTE_DEBUG_WORK, "+"); + _vte_debug_print (VTE_DEBUG_UPDATES, "Draw (%d,%d)x(%d,%d)\n", + clip_rect.x, clip_rect.y, + clip_rect.width, clip_rect.height); - /* Designate the start of the drawing operation and clear the area. */ - _vte_draw_start(terminal->pvt->draw); - if (terminal->pvt->bg_transparent) { - int x, y; - gdk_window_get_origin (gtk_widget_get_window (widget), &x, &y); - _vte_draw_set_background_scroll(terminal->pvt->draw, x, y); - } else { - if (terminal->pvt->scroll_background) { - _vte_draw_set_background_scroll(terminal->pvt->draw, - 0, - terminal->pvt->screen->scroll_delta * - terminal->char_height); - } else { - _vte_draw_set_background_scroll(terminal->pvt->draw, 0, 0); - } - } + region = vte_cairo_get_clip_region (cr); + if (region == NULL) + return FALSE; - _VTE_DEBUG_IF (VTE_DEBUG_UPDATES) { - VteRegionRectangle clip; - gdk_region_get_clipbox (region, &clip); - g_printerr ("vte_terminal_paint" - " (%d,%d)x(%d,%d) pixels\n", - clip.x, clip.y, clip.width, clip.height); - } + allocated_width = gtk_widget_get_allocated_width(widget); + allocated_height = gtk_widget_get_allocated_height(widget); + + /* Designate the start of the drawing operation and clear the area. */ + _vte_draw_set_cairo(terminal->pvt->draw, cr); - _vte_draw_clip(terminal->pvt->draw, region); - gtk_widget_get_allocation(&terminal->widget, &allocation); _vte_draw_clear (terminal->pvt->draw, 0, 0, - allocation.width, allocation.height); + allocated_width, allocated_height); /* Calculate the bounding rectangle. */ { - VteRegionRectangle *rectangles; + cairo_rectangle_int_t *rectangles; gint n, n_rectangles; - gdk_region_get_rectangles (region, &rectangles, &n_rectangles); + n_rectangles = cairo_region_num_rectangles (region); + rectangles = g_new (cairo_rectangle_int_t, n_rectangles); + for (n = 0; n < n_rectangles; n++) { + cairo_region_get_rectangle (region, n, &rectangles[n]); + } + /* don't bother to enlarge an invalidate all */ if (!(n_rectangles == 1 - && rectangles[0].width == allocation.width - && rectangles[0].height == allocation.height)) { - GdkRegion *rr = gdk_region_new (); + && rectangles[0].width == allocated_width + && rectangles[0].height == allocated_height)) { + cairo_region_t *rr = cairo_region_create (); /* convert pixels into whole cells */ for (n = 0; n < n_rectangles; n++) { vte_terminal_expand_region (terminal, rr, rectangles + n); } g_free (rectangles); - gdk_region_get_rectangles (rr, &rectangles, &n_rectangles); - gdk_region_destroy (rr); + + n_rectangles = cairo_region_num_rectangles (rr); + rectangles = g_new (cairo_rectangle_int_t, n_rectangles); + for (n = 0; n < n_rectangles; n++) { + cairo_region_get_rectangle (rr, n, &rectangles[n]); + } + cairo_region_destroy (rr); } /* and now paint them */ @@ -11436,12 +10752,16 @@ vte_terminal_paint(GtkWidget *widget, GdkRegion *region) vte_terminal_paint_im_preedit_string(terminal); /* Done with various structures. */ - _vte_draw_end(terminal->pvt->draw); + _vte_draw_set_cairo(terminal->pvt->draw, NULL); + + cairo_region_destroy (region); + + terminal->pvt->invalidated_all = FALSE; + + return FALSE; } /* Handle an expose event by painting the exposed area. */ -#if GTK_CHECK_VERSION (2, 90, 8) - static cairo_region_t * vte_cairo_get_clip_region (cairo_t *cr) { @@ -11482,153 +10802,92 @@ vte_cairo_get_clip_region (cairo_t *cr) return region; } -static gboolean -vte_terminal_draw(GtkWidget *widget, - cairo_t *cr) -{ - VteTerminal *terminal = VTE_TERMINAL (widget); - cairo_rectangle_int_t clip_rect; - cairo_region_t *region; - - if (!gdk_cairo_get_clip_rectangle (cr, &clip_rect)) - return FALSE; - - _vte_debug_print (VTE_DEBUG_WORK, "+"); - _vte_debug_print (VTE_DEBUG_EVENTS, "Draw (%d,%d)x(%d,%d)\n", - clip_rect.x, clip_rect.y, - clip_rect.width, clip_rect.height); - - region = vte_cairo_get_clip_region (cr); - if (region == NULL) - return FALSE; - - vte_terminal_paint(widget, region); - cairo_region_destroy (region); - - terminal->pvt->invalidated_all = FALSE; - - return FALSE; -} - -#else - -static gboolean -vte_terminal_expose(GtkWidget *widget, - GdkEventExpose *event) -{ - VteTerminal *terminal = VTE_TERMINAL (widget); - GtkAllocation allocation; - - /* Beware the out of order events - - * do not even think about skipping exposes! */ - _vte_debug_print (VTE_DEBUG_WORK, "+"); - _vte_debug_print (VTE_DEBUG_EVENTS, "Expose (%d,%d)x(%d,%d)\n", - event->area.x, event->area.y, - event->area.width, event->area.height); - if (terminal->pvt->active != NULL && - update_timeout_tag != 0 && - !in_update_timeout) { - /* fix up a race condition where we schedule a delayed update - * after an 'immediate' invalidate all */ - if (terminal->pvt->invalidated_all && - terminal->pvt->update_regions == NULL) { - terminal->pvt->invalidated_all = FALSE; - } - /* if we expect to redraw the widget soon, - * just add this event to the list */ - if (!terminal->pvt->invalidated_all) { - gtk_widget_get_allocation (widget, &allocation); - if (event->area.width >= allocation.width && - event->area.height >= allocation.height) { - _vte_invalidate_all (terminal); - } else { - terminal->pvt->update_regions = - g_slist_prepend (terminal->pvt->update_regions, - gdk_region_copy (event->region)); - } - } - } else { - vte_terminal_paint(widget, event->region); - terminal->pvt->invalidated_all = FALSE; - } - return FALSE; -} - -#endif /* GTK 3.0 */ - /* Handle a scroll event. */ static gboolean vte_terminal_scroll(GtkWidget *widget, GdkEventScroll *event) { GtkAdjustment *adj; VteTerminal *terminal; + gdouble delta_x, delta_y; gdouble v; + gint cnt, i; int button; terminal = VTE_TERMINAL(widget); vte_terminal_read_modifiers (terminal, (GdkEvent*) event); - _VTE_DEBUG_IF(VTE_DEBUG_EVENTS) - switch (event->direction) { - case GDK_SCROLL_UP: - g_printerr("Scroll up.\n"); - break; - case GDK_SCROLL_DOWN: - g_printerr("Scroll down.\n"); - break; - default: - break; - } + switch (event->direction) { + case GDK_SCROLL_UP: + terminal->pvt->mouse_smooth_scroll_delta -= 1.; + _vte_debug_print(VTE_DEBUG_EVENTS, "Scroll up\n"); + break; + case GDK_SCROLL_DOWN: + terminal->pvt->mouse_smooth_scroll_delta += 1.; + _vte_debug_print(VTE_DEBUG_EVENTS, "Scroll down\n"); + break; +#if GTK_CHECK_VERSION (3, 4, 0) + case GDK_SCROLL_SMOOTH: + gdk_event_get_scroll_deltas ((GdkEvent*) event, &delta_x, &delta_y); + terminal->pvt->mouse_smooth_scroll_delta += delta_y; + _vte_debug_print(VTE_DEBUG_EVENTS, + "Smooth scroll by %f, delta now at %f\n", + delta_y, terminal->pvt->mouse_smooth_scroll_delta); + break; +#endif + default: + break; + } /* If we're running a mouse-aware application, map the scroll event * to a button press on buttons four and five. */ if (terminal->pvt->mouse_tracking_mode) { - switch (event->direction) { - case GDK_SCROLL_UP: - button = 4; - break; - case GDK_SCROLL_DOWN: - button = 5; - break; - default: - button = 0; - break; - } - if (button != 0) { + cnt = terminal->pvt->mouse_smooth_scroll_delta; + if (cnt == 0) + return TRUE; + terminal->pvt->mouse_smooth_scroll_delta -= cnt; + _vte_debug_print(VTE_DEBUG_EVENTS, + "Scroll application by %d lines, smooth scroll delta set back to %f\n", + cnt, terminal->pvt->mouse_smooth_scroll_delta); + + button = cnt > 0 ? 5 : 4; + if (cnt < 0) + cnt = -cnt; + for (i = 0; i < cnt; i++) { /* Encode the parameters and send them to the app. */ vte_terminal_send_mouse_button_internal(terminal, button, + FALSE /* not release */, event->x, event->y); } return TRUE; } - adj = terminal->adjustment; + adj = terminal->pvt->vadjustment; v = MAX (1., ceil (gtk_adjustment_get_page_increment (adj) / 10.)); - switch (event->direction) { - case GDK_SCROLL_UP: - v = -v; - break; - case GDK_SCROLL_DOWN: - break; - default: - return FALSE; - } + _vte_debug_print(VTE_DEBUG_EVENTS, + "Scroll speed is %d lines per non-smooth scroll unit\n", + (int) v); + cnt = v * terminal->pvt->mouse_smooth_scroll_delta; + if (cnt == 0) + return TRUE; + terminal->pvt->mouse_smooth_scroll_delta -= cnt / v; + _vte_debug_print(VTE_DEBUG_EVENTS, + "Scroll by %d lines, smooth scroll delta set back to %f\n", + cnt, terminal->pvt->mouse_smooth_scroll_delta); - if (terminal->pvt->screen == &terminal->pvt->alternate_screen || - terminal->pvt->normal_screen.scrolling_restricted) { + if (terminal->pvt->screen == &terminal->pvt->alternate_screen && + terminal->pvt->alternate_screen_scroll) { char *normal; gssize normal_length; const gchar *special; - gint i, cnt = v; /* In the alternate screen there is no scrolling, * so fake a few cursor keystrokes. */ _vte_keymap_map ( - cnt > 0 ? GDK_KEY (Down) : GDK_KEY (Up), + cnt > 0 ? GDK_KEY_Down : GDK_KEY_Up, terminal->pvt->modifiers, terminal->pvt->sun_fkey_mode, terminal->pvt->hp_fkey_mode, @@ -11638,7 +10897,7 @@ vte_terminal_scroll(GtkWidget *widget, GdkEventScroll *event) terminal->pvt->keypad_mode == VTE_KEYMODE_APPLICATION, terminal->pvt->termcap, terminal->pvt->emulation ? - terminal->pvt->emulation : vte_terminal_get_default_emulation(terminal), + terminal->pvt->emulation : vte_get_default_emulation(), &normal, &normal_length, &special); @@ -11651,52 +10910,13 @@ vte_terminal_scroll(GtkWidget *widget, GdkEventScroll *event) g_free (normal); } else { /* Perform a history scroll. */ - v += terminal->pvt->screen->scroll_delta; - vte_terminal_queue_adjustment_value_changed_clamped (terminal, v); + cnt += terminal->pvt->screen->scroll_delta; + vte_terminal_queue_adjustment_value_changed_clamped (terminal, cnt); } return TRUE; } -/* Create a new accessible object associated with ourselves, and return - * it to the caller. */ -static AtkObject * -vte_terminal_get_accessible(GtkWidget *widget) -{ - VteTerminal *terminal; - static gboolean first_time = TRUE; - - terminal = VTE_TERMINAL(widget); - - if (first_time) { - AtkObjectFactory *factory; - AtkRegistry *registry; - GType derived_type; - GType derived_atk_type; - - /* - * Figure out whether accessibility is enabled by looking at the - * type of the accessible object which would be created for - * the parent type of VteTerminal. - */ - derived_type = g_type_parent (VTE_TYPE_TERMINAL); - - registry = atk_get_default_registry (); - factory = atk_registry_get_factory (registry, - derived_type); - - derived_atk_type = atk_object_factory_get_accessible_type (factory); - if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) { - atk_registry_set_factory_type (registry, - VTE_TYPE_TERMINAL, - vte_terminal_accessible_factory_get_type ()); - } - first_time = FALSE; - } - - return GTK_WIDGET_CLASS (vte_terminal_parent_class)->get_accessible (widget); -} - static void vte_terminal_get_property (GObject *object, guint prop_id, @@ -11708,12 +10928,11 @@ vte_terminal_get_property (GObject *object, switch (prop_id) { -#if GTK_CHECK_VERSION (2, 91, 2) case PROP_HADJUSTMENT: g_value_set_object (value, pvt->hadjustment); break; case PROP_VADJUSTMENT: - g_value_set_object (value, terminal->adjustment); + g_value_set_object (value, terminal->pvt->vadjustment); break; case PROP_HSCROLL_POLICY: g_value_set_enum (value, pvt->hscroll_policy); @@ -11721,37 +10940,27 @@ vte_terminal_get_property (GObject *object, case PROP_VSCROLL_POLICY: g_value_set_enum (value, pvt->vscroll_policy); break; -#endif case PROP_ALLOW_BOLD: g_value_set_boolean (value, vte_terminal_get_allow_bold (terminal)); break; case PROP_AUDIBLE_BELL: g_value_set_boolean (value, vte_terminal_get_audible_bell (terminal)); break; - case PROP_BACKGROUND_IMAGE_FILE: - g_value_set_string (value, pvt->bg_file); - break; - case PROP_BACKGROUND_IMAGE_PIXBUF: - g_value_set_object (value, pvt->bg_pixbuf); - break; - case PROP_BACKGROUND_OPACITY: - g_value_set_double (value, (double) pvt->bg_opacity / (double) G_MAXUINT16); - break; - case PROP_BACKGROUND_SATURATION: - g_value_set_double (value, (double) pvt->bg_saturation / (double) VTE_SATURATION_MAX); - break; - case PROP_BACKGROUND_TINT_COLOR: - g_value_set_boxed (value, &pvt->bg_tint_color); - break; - case PROP_BACKGROUND_TRANSPARENT: - g_value_set_boolean (value, pvt->bg_transparent); - break; case PROP_BACKSPACE_BINDING: g_value_set_enum (value, pvt->backspace_binding); break; + case PROP_CJK_AMBIGUOUS_WIDTH: + g_value_set_int (value, vte_terminal_get_cjk_ambiguous_width (terminal)); + break; case PROP_CURSOR_BLINK_MODE: g_value_set_enum (value, vte_terminal_get_cursor_blink_mode (terminal)); break; + case PROP_CURRENT_DIRECTORY_URI: + g_value_set_string (value, vte_terminal_get_current_directory_uri (terminal)); + break; + case PROP_CURRENT_FILE_URI: + g_value_set_string (value, vte_terminal_get_current_file_uri (terminal)); + break; case PROP_CURSOR_SHAPE: g_value_set_enum (value, vte_terminal_get_cursor_shape (terminal)); break; @@ -11774,13 +10983,10 @@ vte_terminal_get_property (GObject *object, g_value_set_boolean (value, vte_terminal_get_mouse_autohide (terminal)); break; case PROP_PTY: - g_value_set_int (value, pvt->pty != NULL ? vte_pty_get_fd(pvt->pty) : -1); + g_value_set_object (value, vte_terminal_get_pty(terminal)); break; - case PROP_PTY_OBJECT: - g_value_set_object (value, vte_terminal_get_pty_object(terminal)); - break; - case PROP_SCROLL_BACKGROUND: - g_value_set_boolean (value, pvt->scroll_background); + case PROP_REWRAP_ON_RESIZE: + g_value_set_boolean (value, vte_terminal_get_rewrap_on_resize (terminal)); break; case PROP_SCROLLBACK_LINES: g_value_set_uint (value, pvt->scrollback_lines); @@ -11794,12 +11000,12 @@ vte_terminal_get_property (GObject *object, case PROP_WINDOW_TITLE: g_value_set_string (value, vte_terminal_get_window_title (terminal)); break; - case PROP_WORD_CHARS: - g_value_set_string (value, NULL /* FIXME */); - break; case PROP_VISIBLE_BELL: g_value_set_boolean (value, vte_terminal_get_visible_bell (terminal)); break; + case PROP_FONT_SCALE: + g_value_set_double (value, vte_terminal_get_font_scale (terminal)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -11818,7 +11024,6 @@ vte_terminal_set_property (GObject *object, switch (prop_id) { -#if GTK_CHECK_VERSION (2, 91, 2) case PROP_HADJUSTMENT: vte_terminal_set_hadjustment (terminal, g_value_get_object (value)); break; @@ -11833,34 +11038,18 @@ vte_terminal_set_property (GObject *object, pvt->vscroll_policy = g_value_get_enum (value); gtk_widget_queue_resize_no_redraw (GTK_WIDGET (terminal)); break; -#endif case PROP_ALLOW_BOLD: vte_terminal_set_allow_bold (terminal, g_value_get_boolean (value)); break; case PROP_AUDIBLE_BELL: vte_terminal_set_audible_bell (terminal, g_value_get_boolean (value)); break; - case PROP_BACKGROUND_IMAGE_FILE: - vte_terminal_set_background_image_file (terminal, g_value_get_string (value)); - break; - case PROP_BACKGROUND_IMAGE_PIXBUF: - vte_terminal_set_background_image (terminal, g_value_get_object (value)); - break; - case PROP_BACKGROUND_OPACITY: - vte_terminal_set_opacity (terminal, g_value_get_double (value) * (double) G_MAXUINT16); - break; - case PROP_BACKGROUND_SATURATION: - vte_terminal_set_background_saturation (terminal, g_value_get_double (value)); - break; - case PROP_BACKGROUND_TINT_COLOR: - vte_terminal_set_background_tint_color (terminal, g_value_get_boxed (value)); - break; - case PROP_BACKGROUND_TRANSPARENT: - vte_terminal_set_background_transparent (terminal, g_value_get_boolean (value)); - break; case PROP_BACKSPACE_BINDING: vte_terminal_set_backspace_binding (terminal, g_value_get_enum (value)); break; + case PROP_CJK_AMBIGUOUS_WIDTH: + vte_terminal_set_cjk_ambiguous_width (terminal, g_value_get_int (value)); + break; case PROP_CURSOR_BLINK_MODE: vte_terminal_set_cursor_blink_mode (terminal, g_value_get_enum (value)); break; @@ -11877,19 +11066,16 @@ vte_terminal_set_property (GObject *object, vte_terminal_set_encoding (terminal, g_value_get_string (value)); break; case PROP_FONT_DESC: - vte_terminal_set_font_full_internal (terminal, g_value_get_boxed (value), pvt->fontantialias); + vte_terminal_set_font (terminal, g_value_get_boxed (value)); break; case PROP_MOUSE_POINTER_AUTOHIDE: vte_terminal_set_mouse_autohide (terminal, g_value_get_boolean (value)); break; case PROP_PTY: - vte_terminal_set_pty (terminal, g_value_get_int (value)); - break; - case PROP_PTY_OBJECT: - vte_terminal_set_pty_object (terminal, g_value_get_object (value)); + vte_terminal_set_pty (terminal, g_value_get_object (value)); break; - case PROP_SCROLL_BACKGROUND: - vte_terminal_set_scroll_background (terminal, g_value_get_boolean (value)); + case PROP_REWRAP_ON_RESIZE: + vte_terminal_set_rewrap_on_resize (terminal, g_value_get_boolean (value)); break; case PROP_SCROLLBACK_LINES: vte_terminal_set_scrollback_lines (terminal, g_value_get_uint (value)); @@ -11900,14 +11086,16 @@ vte_terminal_set_property (GObject *object, case PROP_SCROLL_ON_OUTPUT: vte_terminal_set_scroll_on_output (terminal, g_value_get_boolean (value)); break; - case PROP_WORD_CHARS: - vte_terminal_set_word_chars (terminal, g_value_get_string (value)); - break; case PROP_VISIBLE_BELL: vte_terminal_set_visible_bell (terminal, g_value_get_boolean (value)); break; + case PROP_FONT_SCALE: + vte_terminal_set_font_scale (terminal, g_value_get_double (value)); + break; /* Not writable */ + case PROP_CURRENT_DIRECTORY_URI: + case PROP_CURRENT_FILE_URI: case PROP_ICON_TITLE: case PROP_WINDOW_TITLE: g_assert_not_reached (); @@ -11945,7 +11133,6 @@ vte_terminal_class_init(VteTerminalClass *klass) " * _vte_invalidate_all\n" " ) end _vte_terminal_process_incoming\n" " - gdk_window_process_updates\n" - " + vte_terminal_expose\n" " = vte_terminal_paint\n" " ]} end update_timeout\n" " > end process_timeout\n"); @@ -11968,11 +11155,7 @@ vte_terminal_class_init(VteTerminalClass *klass) gobject_class->set_property = vte_terminal_set_property; widget_class->realize = vte_terminal_realize; widget_class->scroll_event = vte_terminal_scroll; -#if GTK_CHECK_VERSION (2, 90, 8) widget_class->draw = vte_terminal_draw; -#else - widget_class->expose_event = vte_terminal_expose; -#endif widget_class->key_press_event = vte_terminal_key_press; widget_class->key_release_event = vte_terminal_key_release; widget_class->button_press_event = vte_terminal_button_press; @@ -11984,15 +11167,10 @@ vte_terminal_class_init(VteTerminalClass *klass) widget_class->focus_out_event = vte_terminal_focus_out; widget_class->visibility_notify_event = vte_terminal_visibility_notify; widget_class->unrealize = vte_terminal_unrealize; - widget_class->style_set = vte_terminal_style_set; -#if GTK_CHECK_VERSION (2, 91, 0) + widget_class->style_updated = vte_terminal_style_updated; widget_class->get_preferred_width = vte_terminal_get_preferred_width; widget_class->get_preferred_height = vte_terminal_get_preferred_height; -#else - widget_class->size_request = vte_terminal_size_request; -#endif widget_class->size_allocate = vte_terminal_size_allocate; - widget_class->get_accessible = vte_terminal_get_accessible; widget_class->screen_changed = vte_terminal_screen_changed; /* Initialize default handlers. */ @@ -12032,49 +11210,14 @@ vte_terminal_class_init(VteTerminalClass *klass) klass->beep = NULL; -#if GTK_CHECK_VERSION (2, 91, 2) /* GtkScrollable interface properties */ g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment"); g_object_class_override_property (gobject_class, PROP_VADJUSTMENT, "vadjustment"); g_object_class_override_property (gobject_class, PROP_HSCROLL_POLICY, "hscroll-policy"); g_object_class_override_property (gobject_class, PROP_VSCROLL_POLICY, "vscroll-policy"); -#else - - klass->set_scroll_adjustments = vte_terminal_set_scroll_adjustments; - - /** - * VteTerminal::set-scroll-adjustments: - * @vteterminal: the object which received the signal - * @horizontal: (allow-none): the horizontal #GtkAdjustment (unused in #VteTerminal) - * @vertical: (allow-none): the vertical #GtkAdjustment - * - * Set the scroll adjustments for the terminal. Usually scrolled containers - * like #GtkScrolledWindow will emit this signal to connect two instances - * of #GtkScrollbar to the scroll directions of the #VteTerminal. - * - * Since: 0.17.1 - */ - widget_class->set_scroll_adjustments_signal = - g_signal_new(I_("set-scroll-adjustments"), - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (VteTerminalClass, set_scroll_adjustments), - NULL, NULL, - _vte_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, 2, - GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); - -#endif - /* Register some signals of our own. */ -#if GTK_CHECK_VERSION (2, 99, 0) -#define OBSOLETE_SIGNAL(str) -#else -#define OBSOLETE_SIGNAL(str) str -#endif - /** * VteTerminal::eof: * @vteterminal: the object which received the signal @@ -12083,32 +11226,32 @@ vte_terminal_class_init(VteTerminalClass *klass) * is running in the terminal. This signal is frequently (but not * always) emitted with a #VteTerminal::child-exited signal. */ - OBSOLETE_SIGNAL (klass->eof_signal =) - g_signal_new(I_("eof"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, eof), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("eof"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, eof), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::child-exited: * @vteterminal: the object which received the signal + * @status: the child's exit status * - * This signal is emitted when the terminal detects that a child started - * using vte_terminal_fork_command() has exited. + * This signal is emitted when the terminal detects that a child + * watched using vte_terminal_watch_child() has exited. */ - OBSOLETE_SIGNAL (klass->child_exited_signal =) - g_signal_new(I_("child-exited"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, child_exited), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("child-exited"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, child_exited), + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, G_TYPE_INT); /** * VteTerminal::window-title-changed: @@ -12116,15 +11259,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted when the terminal's %window_title field is modified. */ - OBSOLETE_SIGNAL (klass->window_title_changed_signal =) - g_signal_new(I_("window-title-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, window_title_changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("window-title-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, window_title_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::icon-title-changed: @@ -12132,15 +11274,48 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted when the terminal's %icon_title field is modified. */ - OBSOLETE_SIGNAL (klass->icon_title_changed_signal =) - g_signal_new(I_("icon-title-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, icon_title_changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("icon-title-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, icon_title_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * VteTerminal::current-directory-uri-changed: + * @vteterminal: the object which received the signal + * + * Emitted when the current directory URI is modified. + * + * Since: 0.34 + */ + g_signal_new(I_("current-directory-uri-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * VteTerminal::current-file-uri-changed: + * @vteterminal: the object which received the signal + * + * Emitted when the current file URI is modified. + * + * Since: 0.34 + */ + g_signal_new(I_("current-file-uri-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::encoding-changed: @@ -12150,15 +11325,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * as a result of receiving a control sequence which toggled between the * local and UTF-8 encodings, or at the parent application's request. */ - OBSOLETE_SIGNAL (klass->encoding_changed_signal =) - g_signal_new(I_("encoding-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, encoding_changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("encoding-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, encoding_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::commit: @@ -12170,15 +11344,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * prepares to send it to the child process. The signal is emitted even * when there is no child process. */ - OBSOLETE_SIGNAL (klass->commit_signal =) - g_signal_new(I_("commit"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, commit), - NULL, - NULL, - _vte_marshal_VOID__STRING_UINT, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); + g_signal_new(I_("commit"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, commit), + NULL, + NULL, + _vte_marshal_VOID__STRING_UINT, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); /** * VteTerminal::emulation-changed: @@ -12187,15 +11360,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * Emitted whenever the terminal's emulation changes, only possible at * the parent application's request. */ - OBSOLETE_SIGNAL (klass->emulation_changed_signal =) - g_signal_new(I_("emulation-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, emulation_changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("emulation-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, emulation_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::char-size-changed: @@ -12206,15 +11378,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * Emitted whenever selection of a new font causes the values of the * %char_width or %char_height fields to change. */ - OBSOLETE_SIGNAL (klass->char_size_changed_signal =) - g_signal_new(I_("char-size-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, char_size_changed), - NULL, - NULL, - _vte_marshal_VOID__UINT_UINT, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + g_signal_new(I_("char-size-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, char_size_changed), + NULL, + NULL, + _vte_marshal_VOID__UINT_UINT, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); /** * VteTerminal::selection-changed: @@ -12222,15 +11393,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted whenever the contents of terminal's selection changes. */ - OBSOLETE_SIGNAL (klass->selection_changed_signal =) - g_signal_new (I_("selection-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, selection_changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new (I_("selection-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, selection_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::contents-changed: @@ -12239,15 +11409,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * Emitted whenever the visible appearance of the terminal has changed. * Used primarily by #VteTerminalAccessible. */ - OBSOLETE_SIGNAL (klass->contents_changed_signal =) - g_signal_new(I_("contents-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, contents_changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("contents-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, contents_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::cursor-moved: @@ -12256,15 +11425,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * Emitted whenever the cursor moves to a new character cell. Used * primarily by #VteTerminalAccessible. */ - OBSOLETE_SIGNAL (klass->cursor_moved_signal =) - g_signal_new(I_("cursor-moved"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, cursor_moved), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("cursor-moved"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, cursor_moved), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::deiconify-window: @@ -12272,15 +11440,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->deiconify_window_signal =) - g_signal_new(I_("deiconify-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, deiconify_window), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("deiconify-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, deiconify_window), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::iconify-window: @@ -12288,15 +11455,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->iconify_window_signal =) - g_signal_new(I_("iconify-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, iconify_window), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("iconify-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, iconify_window), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::raise-window: @@ -12304,15 +11470,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->raise_window_signal =) - g_signal_new(I_("raise-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, raise_window), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("raise-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, raise_window), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::lower-window: @@ -12320,15 +11485,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->lower_window_signal =) - g_signal_new(I_("lower-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, lower_window), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("lower-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, lower_window), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::refresh-window: @@ -12336,15 +11500,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->refresh_window_signal =) - g_signal_new(I_("refresh-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, refresh_window), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("refresh-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, refresh_window), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::restore-window: @@ -12352,15 +11515,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->restore_window_signal =) - g_signal_new(I_("restore-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, restore_window), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("restore-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, restore_window), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::maximize-window: @@ -12368,15 +11530,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->maximize_window_signal =) - g_signal_new(I_("maximize-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, maximize_window), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("maximize-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, maximize_window), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::resize-window: @@ -12386,15 +11547,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->resize_window_signal =) - g_signal_new(I_("resize-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, resize_window), - NULL, - NULL, - _vte_marshal_VOID__UINT_UINT, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + g_signal_new(I_("resize-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, resize_window), + NULL, + NULL, + _vte_marshal_VOID__UINT_UINT, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); /** * VteTerminal::move-window: @@ -12404,15 +11564,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted at the child application's request. */ - OBSOLETE_SIGNAL (klass->move_window_signal =) - g_signal_new(I_("move-window"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, move_window), - NULL, - NULL, - _vte_marshal_VOID__UINT_UINT, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + g_signal_new(I_("move-window"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, move_window), + NULL, + NULL, + _vte_marshal_VOID__UINT_UINT, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); /** * VteTerminal::status-line-changed: @@ -12421,15 +11580,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * Emitted whenever the contents of the status line are modified or * cleared. */ - OBSOLETE_SIGNAL (klass->status_line_changed_signal =) - g_signal_new(I_("status-line-changed"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, status_line_changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("status-line-changed"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, status_line_changed), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::increase-font-size: @@ -12437,15 +11595,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted when the user hits the '+' key while holding the Control key. */ - OBSOLETE_SIGNAL (klass->increase_font_size_signal =) - g_signal_new(I_("increase-font-size"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, increase_font_size), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("increase-font-size"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, increase_font_size), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::decrease-font-size: @@ -12453,15 +11610,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * * Emitted when the user hits the '-' key while holding the Control key. */ - OBSOLETE_SIGNAL (klass->decrease_font_size_signal =) - g_signal_new(I_("decrease-font-size"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, decrease_font_size), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("decrease-font-size"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, decrease_font_size), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::text-modified: @@ -12471,15 +11627,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * its accessibility peer. May not be emitted under certain * circumstances. */ - OBSOLETE_SIGNAL (klass->text_modified_signal =) - g_signal_new(I_("text-modified"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, text_modified), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("text-modified"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, text_modified), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::text-inserted: @@ -12489,15 +11644,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * its accessibility peer. May not be emitted under certain * circumstances. */ - OBSOLETE_SIGNAL (klass->text_inserted_signal =) - g_signal_new(I_("text-inserted"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, text_inserted), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("text-inserted"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, text_inserted), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::text-deleted: @@ -12507,15 +11661,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * its accessibility peer. May not be emitted under certain * circumstances. */ - OBSOLETE_SIGNAL (klass->text_deleted_signal =) - g_signal_new(I_("text-deleted"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, text_deleted), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new(I_("text-deleted"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, text_deleted), + NULL, + NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * VteTerminal::text-scrolled: @@ -12526,17 +11679,14 @@ vte_terminal_class_init(VteTerminalClass *klass) * its accessibility peer. May not be emitted under certain * circumstances. */ - OBSOLETE_SIGNAL (klass->text_scrolled_signal =) - g_signal_new(I_("text-scrolled"), - G_OBJECT_CLASS_TYPE(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(VteTerminalClass, text_scrolled), - NULL, - NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - -#undef OBSOLETE_SIGNAL + g_signal_new(I_("text-scrolled"), + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(VteTerminalClass, text_scrolled), + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); /** * VteTerminal::copy-clipboard: @@ -12600,7 +11750,7 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_ALLOW_BOLD, g_param_spec_boolean ("allow-bold", NULL, NULL, TRUE, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:audible-bell: @@ -12615,134 +11765,42 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_AUDIBLE_BELL, g_param_spec_boolean ("audible-bell", NULL, NULL, TRUE, - G_PARAM_READWRITE | STATIC_PARAMS)); - - /** - * VteTerminal:background-image-file: (type filename): - * - * Sets a background image file for the widget. If specified by - * #VteTerminal:background-saturation:, the terminal will tint its - * in-memory copy of the image before applying it to the terminal. - * - * Since: 0.20 - */ - g_object_class_install_property - (gobject_class, - PROP_BACKGROUND_IMAGE_FILE, - g_param_spec_string ("background-image-file", NULL, NULL, - NULL, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * VteTerminal:background-image-pixbuf: + * VteTerminal:backspace-binding: * - * Sets a background image for the widget. Text which would otherwise be - * drawn using the default background color will instead be drawn over the - * specified image. If necessary, the image will be tiled to cover the - * widget's entire visible area. If specified by - * #VteTerminal:background-saturation:, the terminal will tint its - * in-memory copy of the image before applying it to the terminal. + * *Controls what string or control sequence the terminal sends to its child + * when the user presses the backspace key. * * Since: 0.20 */ g_object_class_install_property (gobject_class, - PROP_BACKGROUND_IMAGE_PIXBUF, - g_param_spec_object ("background-image-pixbuf", NULL, NULL, - GDK_TYPE_PIXBUF, - G_PARAM_READWRITE | STATIC_PARAMS)); + PROP_BACKSPACE_BINDING, + g_param_spec_enum ("backspace-binding", NULL, NULL, + VTE_TYPE_ERASE_BINDING, + VTE_ERASE_AUTO, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * VteTerminal:background-opacity: - * - * Sets the opacity of the terminal background, were 0.0 means completely - * transparent and 1.0 means completely opaque. - * - * Since: 0.20 - */ - g_object_class_install_property - (gobject_class, - PROP_BACKGROUND_OPACITY, - g_param_spec_double ("background-opacity", NULL, NULL, - 0.0, 1.0, - 1.0, - G_PARAM_READWRITE | STATIC_PARAMS)); - - /** - * VteTerminal:background-saturation: - * - * If a background image has been set using #VteTerminal:background-image-file: or - * #VteTerminal:background-image-pixbuf:, or #VteTerminal:background-transparent:, - * and the saturation value is less - * than 1.0, the terminal will adjust the colors of the image before drawing - * the image. To do so, the terminal will create a copy of the background - * image (or snapshot of the root window) and modify its pixel values. - * - * Since: 0.20 - */ - g_object_class_install_property - (gobject_class, - PROP_BACKGROUND_SATURATION, - g_param_spec_double ("background-saturation", NULL, NULL, - 0.0, 1.0, - 0.4, - G_PARAM_READWRITE | STATIC_PARAMS)); - - /** - * VteTerminal:background-tint-color: - * - * If a background image has been set using #VteTerminal:background-image-file: or - * #VteTerminal:background-image-pixbuf:, or #VteTerminal:background-transparent:, and - * and the value set by VteTerminal:background-saturation: is less than 1.0, - * the terminal - * will adjust the color of the image before drawing the image. To do so, - * the terminal will create a copy of the background image (or snapshot of - * the root window) and modify its pixel values. The initial tint color - * is black. - * - * Since: 0.20 - */ - g_object_class_install_property - (gobject_class, - PROP_BACKGROUND_TINT_COLOR, - g_param_spec_boxed ("background-tint-color", NULL, NULL, - GDK_TYPE_COLOR, - G_PARAM_READWRITE | STATIC_PARAMS)); - - /** - * VteTerminal:background-transparent: - * - * Sets whther the terminal uses the pixmap stored in the root - * window as the background, adjusted so that if there are no windows - * below your application, the widget will appear to be transparent. + * VteTerminal:cjk-ambiguous-width: * - * Note: When using a compositing window manager, you should instead - * set a RGBA colourmap on the toplevel window, so you get real transparency. - * - * Since: 0.20 - */ - g_object_class_install_property - (gobject_class, - PROP_BACKGROUND_TRANSPARENT, - g_param_spec_boolean ("background-transparent", NULL, NULL, - FALSE, - G_PARAM_READWRITE | STATIC_PARAMS)); - - /** - * VteTerminal:backspace-binding: + * This setting controls whether ambiguous-width characters are narrow or wide + * when using the UTF-8 encoding (vte_terminal_set_encoding()). In all other encodings, + * the width of ambiguous-width characters is fixed. * - * *Controls what string or control sequence the terminal sends to its child - * when the user presses the backspace key. + * This setting only takes effect the next time the terminal is reset, either + * via escape sequence or with vte_terminal_reset(). * - * Since: 0.20 + * Since: 0.38 */ g_object_class_install_property (gobject_class, - PROP_BACKSPACE_BINDING, - g_param_spec_enum ("backspace-binding", NULL, NULL, - VTE_TYPE_TERMINAL_ERASE_BINDING, - VTE_ERASE_AUTO, - G_PARAM_READWRITE | STATIC_PARAMS)); + PROP_CURSOR_BLINK_MODE, + g_param_spec_int ("cjk-ambiguous-width", NULL, NULL, + 1, 2, VTE_ISO2022_DEFAULT_UTF8_AMBIGUOUS_WIDTH, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:cursor-blink-mode: @@ -12756,10 +11814,10 @@ vte_terminal_class_init(VteTerminalClass *klass) (gobject_class, PROP_CURSOR_BLINK_MODE, g_param_spec_enum ("cursor-blink-mode", NULL, NULL, - VTE_TYPE_TERMINAL_CURSOR_BLINK_MODE, + VTE_TYPE_CURSOR_BLINK_MODE, VTE_CURSOR_BLINK_SYSTEM, - G_PARAM_READWRITE | STATIC_PARAMS)); - + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * VteTerminal:cursor-shape: * @@ -12771,9 +11829,9 @@ vte_terminal_class_init(VteTerminalClass *klass) (gobject_class, PROP_CURSOR_SHAPE, g_param_spec_enum ("cursor-shape", NULL, NULL, - VTE_TYPE_TERMINAL_CURSOR_SHAPE, + VTE_TYPE_CURSOR_SHAPE, VTE_CURSOR_SHAPE_BLOCK, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:delete-binding: @@ -12787,9 +11845,9 @@ vte_terminal_class_init(VteTerminalClass *klass) (gobject_class, PROP_DELETE_BINDING, g_param_spec_enum ("delete-binding", NULL, NULL, - VTE_TYPE_TERMINAL_ERASE_BINDING, + VTE_TYPE_ERASE_BINDING, VTE_ERASE_AUTO, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:emulation: @@ -12805,8 +11863,24 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_EMULATION, g_param_spec_string ("emulation", NULL, NULL, VTE_DEFAULT_EMULATION, - G_PARAM_READWRITE | STATIC_PARAMS)); - + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * VteTerminal:font-scale: + * + * The terminal's font scale. + * + * Since: 0.30 + */ + g_object_class_install_property + (gobject_class, + PROP_AUDIBLE_BELL, + g_param_spec_double ("font-scale", NULL, NULL, + VTE_FONT_SCALE_MIN, + VTE_FONT_SCALE_MAX, + 1., + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * VteTerminal:encoding: * @@ -12822,7 +11896,7 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_ENCODING, g_param_spec_string ("encoding", NULL, NULL, NULL, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:font-desc: @@ -12840,7 +11914,7 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_FONT_DESC, g_param_spec_boxed ("font-desc", NULL, NULL, PANGO_TYPE_FONT_DESCRIPTION, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:icon-title: @@ -12854,7 +11928,7 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_ICON_TITLE, g_param_spec_string ("icon-title", NULL, NULL, NULL, - G_PARAM_READABLE | STATIC_PARAMS)); + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:pointer-autohide: @@ -12870,27 +11944,10 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_MOUSE_POINTER_AUTOHIDE, g_param_spec_boolean ("pointer-autohide", NULL, NULL, FALSE, - G_PARAM_READWRITE | STATIC_PARAMS)); - - /** - * VteTerminal:pty: - * - * The file descriptor of the master end of the terminal's PTY. - * - * Since: 0.20 - * - * Deprecated: 0.26: Use the #VteTerminal:pty-object property instead - */ - g_object_class_install_property - (gobject_class, - PROP_PTY, - g_param_spec_int ("pty", NULL, NULL, - -1, G_MAXINT, - -1, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * VteTerminal:pty-object: + * VteTerminal:pty: * * The PTY object for the terminal. * @@ -12898,27 +11955,27 @@ vte_terminal_class_init(VteTerminalClass *klass) */ g_object_class_install_property (gobject_class, - PROP_PTY_OBJECT, - g_param_spec_object ("pty-object", NULL, NULL, + PROP_PTY, + g_param_spec_object ("pty", NULL, NULL, VTE_TYPE_PTY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * VteTerminal:scroll-background: + * VteTerminal:rewrap-on-resize: * - * Controls whether or not the terminal will scroll the background image (if - * one is set) when the text in the window must be scrolled. + * Controls whether or not the terminal will rewrap its contents, including + * the scrollback buffer, whenever the terminal's width changes. * - * Since: 0.20 + * Since: 0.36 */ g_object_class_install_property (gobject_class, - PROP_SCROLL_BACKGROUND, - g_param_spec_boolean ("scroll-background", NULL, NULL, - FALSE, - G_PARAM_READWRITE | STATIC_PARAMS)); - + PROP_REWRAP_ON_RESIZE, + g_param_spec_boolean ("rewrap-on-resize", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * VteTerminal:scrollback-lines: * @@ -12937,7 +11994,7 @@ vte_terminal_class_init(VteTerminalClass *klass) g_param_spec_uint ("scrollback-lines", NULL, NULL, 0, G_MAXUINT, VTE_SCROLLBACK_INIT, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:scroll-on-keystroke: @@ -12953,7 +12010,7 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_SCROLL_ON_KEYSTROKE, g_param_spec_boolean ("scroll-on-keystroke", NULL, NULL, FALSE, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:scroll-on-output: @@ -12968,7 +12025,7 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_SCROLL_ON_OUTPUT, g_param_spec_boolean ("scroll-on-output", NULL, NULL, TRUE, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * VteTerminal:window-title: @@ -12982,28 +12039,36 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_WINDOW_TITLE, g_param_spec_string ("window-title", NULL, NULL, NULL, - G_PARAM_READABLE | STATIC_PARAMS)); - + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** - * VteTerminal:word-chars: + * VteTerminal:current-directory-uri: * - * When the user double-clicks to start selection, the terminal will extend - * the selection on word boundaries. It will treat characters the word-chars - * characters as parts of words, and all other characters as word separators. - * Ranges of characters can be specified by separating them with a hyphen. + * The current directory URI, or %NULL if unset. * - * As a special case, when setting this to %NULL or the empty string, the terminal will - * treat all graphic non-punctuation non-space characters as word characters. - * - * Since: 0.20 + * Since: 0.34 */ g_object_class_install_property (gobject_class, - PROP_WORD_CHARS, - g_param_spec_string ("word-chars", NULL, NULL, + PROP_CURRENT_DIRECTORY_URI, + g_param_spec_string ("current-directory-uri", NULL, NULL, NULL, - G_PARAM_READWRITE | STATIC_PARAMS)); - + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * VteTerminal:current-file-uri: + * + * The current file URI, or %NULL if unset. + * + * Since: 0.34 + */ + g_object_class_install_property + (gobject_class, + PROP_CURRENT_FILE_URI, + g_param_spec_string ("current-file-uri", NULL, NULL, + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** * VteTerminal:visible-bell: * @@ -13018,52 +12083,35 @@ vte_terminal_class_init(VteTerminalClass *klass) PROP_VISIBLE_BELL, g_param_spec_boolean ("visible-bell", NULL, NULL, FALSE, - G_PARAM_READWRITE | STATIC_PARAMS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /* Style properties */ - /** - * VteTerminal:inner-border: - * - * Sets the border around the terminal. - * - * Since: 0.24 - */ - gtk_widget_class_install_style_property - (widget_class, - g_param_spec_boxed ("inner-border", NULL, NULL, - GTK_TYPE_BORDER, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - -#if !GTK_CHECK_VERSION (2,99, 0) - /* Now install the default style */ - gtk_rc_parse_string("style \"vte-default-style\" {\n" - "VteTerminal::inner-border = { 1, 1, 1, 1 }\n" - "}\n" - "class \"VteTerminal\" style : gtk \"vte-default-style\"\n"); -#endif - /* Keybindings */ binding_set = gtk_binding_set_by_class(klass); /* Bind Copy, Paste, Cut keys */ - gtk_binding_entry_add_signal(binding_set, GDK_KEY (F16), 0, "copy-clipboard",0); - gtk_binding_entry_add_signal(binding_set, GDK_KEY (F18), 0, "paste-clipboard", 0); - gtk_binding_entry_add_signal(binding_set, GDK_KEY (F20), 0, "copy-clipboard",0); + gtk_binding_entry_add_signal(binding_set, GDK_KEY_F16, 0, "copy-clipboard",0); + gtk_binding_entry_add_signal(binding_set, GDK_KEY_F18, 0, "paste-clipboard", 0); + gtk_binding_entry_add_signal(binding_set, GDK_KEY_F20, 0, "copy-clipboard",0); + + /* Disable GTK's builtin handler for Ctrl+F1, see bug 726438 */ + binding_set = gtk_binding_set_by_class(vte_terminal_parent_class); + gtk_binding_entry_skip(binding_set, GDK_KEY_F1, GDK_CONTROL_MASK); process_timer = g_timer_new (); -#if GTK_CHECK_VERSION (2, 99, 0) klass->priv = G_TYPE_CLASS_GET_PRIVATE (klass, VTE_TYPE_TERMINAL, VteTerminalClassPrivate); klass->priv->style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ()); gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (klass->priv->style_provider), "VteTerminal {\n" - "-VteTerminal-inner-border: 1;\n" + "padding: 1px 1px 1px 1px;\n" "}\n", -1, NULL); -#endif /* GTK 3.0 */ + + /* a11y */ + gtk_widget_class_set_accessible_type(widget_class, VTE_TYPE_TERMINAL_ACCESSIBLE); } /** @@ -13199,37 +12247,6 @@ vte_terminal_get_allow_bold(VteTerminal *terminal) } /** - * vte_terminal_set_scroll_background: - * @terminal: a #VteTerminal - * @scroll: whether the terminal should scroll the background image along with - * the text - * - * Controls whether or not the terminal will scroll the background image (if - * one is set) when the text in the window must be scrolled. - * - * Since: 0.11 - */ -void -vte_terminal_set_scroll_background(VteTerminal *terminal, gboolean scroll) -{ - VteTerminalPrivate *pvt; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - - pvt = terminal->pvt; - - scroll = scroll != FALSE; - if (scroll == pvt->scroll_background) - return; - - pvt->scroll_background = scroll; - - g_object_notify (G_OBJECT (terminal), "scroll-background"); - - vte_terminal_queue_background_update(terminal); -} - -/** * vte_terminal_set_scroll_on_output: * @terminal: a #VteTerminal * @scroll: whether the terminal should scroll on output @@ -13272,6 +12289,57 @@ vte_terminal_set_scroll_on_keystroke(VteTerminal *terminal, gboolean scroll) } /** + * vte_terminal_set_rewrap_on_resize: + * @terminal: a #VteTerminal + * @rewrap: %TRUE if the terminal should rewrap on resize + * + * Controls whether or not the terminal will rewrap its contents, including + * the scrollback history, whenever the terminal's width changes. + * + * Since: 0.36 + */ +void +vte_terminal_set_rewrap_on_resize(VteTerminal *terminal, gboolean rewrap) +{ + VteTerminalPrivate *pvt; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + + pvt = terminal->pvt; + + if (rewrap == pvt->rewrap_on_resize) + return; + + pvt->rewrap_on_resize = rewrap; + g_object_notify (G_OBJECT (terminal), "rewrap-on-resize"); +} + +/** + * vte_terminal_get_rewrap_on_resize: + * @terminal: a #VteTerminal + * + * Checks whether or not the terminal will rewrap its contents upon resize. + * + * Returns: %TRUE if rewrapping is enabled, %FALSE if not + * + * Since: 0.36 + */ +gboolean +vte_terminal_get_rewrap_on_resize(VteTerminal *terminal) +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE); + return terminal->pvt->rewrap_on_resize; +} + +/* Place the selected text onto the CLIPBOARD clipboard. Do this + * asynchronously, so that we can support the html target as well */ +static void +vte_terminal_real_copy_clipboard(VteTerminal *terminal) +{ + vte_terminal_copy(terminal, VTE_SELECTION_CLIPBOARD); +} + +/** * vte_terminal_copy_clipboard: * @terminal: a #VteTerminal * @@ -13341,360 +12409,37 @@ vte_terminal_paste_primary(VteTerminal *terminal) vte_terminal_paste(terminal, GDK_SELECTION_PRIMARY); } -/** - * vte_terminal_im_append_menuitems: - * @terminal: a #VteTerminal - * @menushell: a GtkMenuShell - * - * Appends menu items for various input methods to the given menu. The - * user can select one of these items to modify the input method used by - * the terminal. - */ -void -vte_terminal_im_append_menuitems(VteTerminal *terminal, GtkMenuShell *menushell) -{ - GtkIMMulticontext *context; - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail (gtk_widget_get_realized (&terminal->widget)); - g_return_if_fail(GTK_IS_MENU_SHELL(menushell)); - context = GTK_IM_MULTICONTEXT(terminal->pvt->im_context); - gtk_im_multicontext_append_menuitems(context, menushell); -} - /* Set up whatever background we wanted. */ -static gboolean +static void vte_terminal_background_update(VteTerminal *terminal) { - double saturation; const PangoColor *entry; - GdkColor color; + GdkRGBA color; /* If we're not realized yet, don't worry about it, because we get * called when we realize. */ if (! gtk_widget_get_realized (&terminal->widget)) { - _vte_debug_print(VTE_DEBUG_MISC, - "Can not set background image without " - "window.\n"); - return TRUE; + return; } _vte_debug_print(VTE_DEBUG_MISC|VTE_DEBUG_EVENTS, - "Updating background image.\n"); + "Updating background color.\n"); - entry = &terminal->pvt->palette[VTE_DEF_BG]; - _vte_debug_print(VTE_DEBUG_BG, - "Setting background color to (%d, %d, %d, %d).\n", + entry = _vte_terminal_get_color(terminal, VTE_DEFAULT_BG); + _vte_debug_print(VTE_DEBUG_STYLE, + "Setting background color to (%d, %d, %d, %.3f).\n", entry->red, entry->green, entry->blue, - terminal->pvt->bg_opacity); - - /* Set the terminal widget background color since otherwise we - * won't draw it for VTE_BG_SOURCE_NONE. */ - color.red = entry->red; - color.green = entry->green; - color.blue = entry->blue; - gtk_widget_modify_bg (&terminal->widget, GTK_STATE_NORMAL, &color); - - _vte_draw_set_background_solid (terminal->pvt->draw, - entry->red / 65535., - entry->green / 65535., - entry->blue / 65535., - terminal->pvt->bg_opacity / 65535.); - - /* If we're transparent, and either have no root image or are being - * told to update it, get a new copy of the root window. */ - saturation = (double) terminal->pvt->bg_saturation; - saturation /= VTE_SATURATION_MAX; - if (terminal->pvt->bg_transparent) { - if (terminal->pvt->root_pixmap_changed_tag == 0) { - VteBg *bg; - - /* Connect to background-change events. */ - bg = vte_bg_get_for_screen (gtk_widget_get_screen (&terminal->widget)); - terminal->pvt->root_pixmap_changed_tag = - g_signal_connect(bg, "root-pixmap-changed", - G_CALLBACK(root_pixmap_changed_cb), - terminal); - } - - _vte_draw_set_background_image(terminal->pvt->draw, - VTE_BG_SOURCE_ROOT, - NULL, - NULL, - &terminal->pvt->bg_tint_color, - saturation); - } else - if (terminal->pvt->bg_file) { - _vte_draw_set_background_image(terminal->pvt->draw, - VTE_BG_SOURCE_FILE, - NULL, - terminal->pvt->bg_file, - &terminal->pvt->bg_tint_color, - saturation); - } else - if (GDK_IS_PIXBUF(terminal->pvt->bg_pixbuf)) { - _vte_draw_set_background_image(terminal->pvt->draw, - VTE_BG_SOURCE_PIXBUF, - terminal->pvt->bg_pixbuf, - NULL, - &terminal->pvt->bg_tint_color, - saturation); - } else { - _vte_draw_set_background_image(terminal->pvt->draw, - VTE_BG_SOURCE_NONE, - NULL, - NULL, - &terminal->pvt->bg_tint_color, - saturation); - } + terminal->pvt->background_alpha); + + color.red = entry->red / 65535.; + color.green = entry->green / 65535.; + color.blue = entry->blue / 65535.; + color.alpha = terminal->pvt->background_alpha; - /* Note that the update has finished. */ - terminal->pvt->bg_update_pending = FALSE; + _vte_draw_set_background_solid (terminal->pvt->draw, &color); /* Force a redraw for everything. */ _vte_invalidate_all (terminal); - - return FALSE; -} - -/* Queue an update of the background image, to be done as soon as we can - * get to it. Just bail if there's already an update pending, so that if - * opaque move tables to screw us, we don't end up with an insane backlog - * of updates after the user finishes moving us. */ -static void -vte_terminal_queue_background_update(VteTerminal *terminal) -{ - _vte_debug_print(VTE_DEBUG_EVENTS, - "Queued background update.\n"); - terminal->pvt->bg_update_pending = TRUE; - /* force a redraw when convenient */ - add_update_timeout (terminal); -} - -/** - * vte_terminal_set_background_saturation: - * @terminal: a #VteTerminal - * @saturation: a floating point value between 0.0 and 1.0. - * - * If a background image has been set using - * vte_terminal_set_background_image(), - * vte_terminal_set_background_image_file(), or - * vte_terminal_set_background_transparent(), and the saturation value is less - * than 1.0, the terminal will adjust the colors of the image before drawing - * the image. To do so, the terminal will create a copy of the background - * image (or snapshot of the root window) and modify its pixel values. - */ -void -vte_terminal_set_background_saturation(VteTerminal *terminal, double saturation) -{ - VteTerminalPrivate *pvt; - guint v; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - - pvt = terminal->pvt; - - v = CLAMP(saturation * VTE_SATURATION_MAX, 0, VTE_SATURATION_MAX); - if (v == pvt->bg_saturation) - return; - - _vte_debug_print(VTE_DEBUG_MISC, - "Setting background saturation to %d/%d.\n", - v, VTE_SATURATION_MAX); - - pvt->bg_saturation = v; - g_object_notify(G_OBJECT (terminal), "background-saturation"); - - vte_terminal_queue_background_update(terminal); -} - -/** - * vte_terminal_set_background_tint_color: - * @terminal: a #VteTerminal - * @color: a color which the terminal background should be tinted to if its - * saturation is not 1.0. - * - * If a background image has been set using - * vte_terminal_set_background_image(), - * vte_terminal_set_background_image_file(), or - * vte_terminal_set_background_transparent(), and the value set by - * vte_terminal_set_background_saturation() is less than one, the terminal - * will adjust the color of the image before drawing the image. To do so, - * the terminal will create a copy of the background image (or snapshot of - * the root window) and modify its pixel values. The initial tint color - * is black. - * - * Since: 0.11 - */ -void -vte_terminal_set_background_tint_color(VteTerminal *terminal, - const GdkColor *color) -{ - VteTerminalPrivate *pvt; - PangoColor *tint; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(color != NULL); - - pvt = terminal->pvt; - - _vte_debug_print(VTE_DEBUG_MISC, - "Setting background tint to %d,%d,%d.\n", - terminal->pvt->bg_tint_color.red >> 8, - terminal->pvt->bg_tint_color.green >> 8, - terminal->pvt->bg_tint_color.blue >> 8); - tint = &pvt->bg_tint_color; - if (color->red == tint->red && - color->green == tint->green && - color->blue == tint->blue) - return; - - tint->red = color->red; - tint->green = color->green; - tint->blue = color->blue; - - g_object_notify(G_OBJECT (terminal), "background-tint-color"); - - vte_terminal_queue_background_update(terminal); -} - -/** - * vte_terminal_set_background_transparent: - * @terminal: a #VteTerminal - * @transparent: whether the terminal should fake transparency - * - * Sets the terminal's background image to the pixmap stored in the root - * window, adjusted so that if there are no windows below your application, - * the widget will appear to be transparent. - */ -void -vte_terminal_set_background_transparent(VteTerminal *terminal, - gboolean transparent) -{ - VteTerminalPrivate *pvt; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - - pvt = terminal->pvt; - - transparent = transparent != FALSE; - if (transparent == pvt->bg_transparent) - return; - - _vte_debug_print(VTE_DEBUG_MISC, - "Turning background transparency %s.\n", - transparent ? "on" : "off"); - - pvt->bg_transparent = transparent; - g_object_notify(G_OBJECT (terminal), "background-transparent"); - - /* Update the background. */ - vte_terminal_queue_background_update(terminal); -} - -/** - * vte_terminal_set_background_image: - * @terminal: a #VteTerminal - * @image: (allow-none): a #GdkPixbuf to use, or %NULL to unset the background - * - * Sets a background image for the widget. Text which would otherwise be - * drawn using the default background color will instead be drawn over the - * specified image. If necessary, the image will be tiled to cover the - * widget's entire visible area. If specified by - * vte_terminal_set_background_saturation(), the terminal will tint its - * in-memory copy of the image before applying it to the terminal. - */ -void -vte_terminal_set_background_image(VteTerminal *terminal, GdkPixbuf *image) -{ - VteTerminalPrivate *pvt; - GObject *object; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(image==NULL || GDK_IS_PIXBUF(image)); - - object = G_OBJECT(terminal); - pvt = terminal->pvt; - - if (image && image == pvt->bg_pixbuf) - return; - - _vte_debug_print(VTE_DEBUG_MISC, - "%s background image.\n", - GDK_IS_PIXBUF(image) ? "Setting" : "Clearing"); - - g_object_freeze_notify(object); - - /* Get a ref to the new image if there is one. Do it here just in - * case we're actually given the same one we're already using. */ - if (image != NULL) { - g_object_ref(image); - } - - /* Unref the previous background image. */ - if (pvt->bg_pixbuf != NULL) { - g_object_unref(pvt->bg_pixbuf); - } - - /* Clear a background file name, if one was set. */ - if (pvt->bg_file) { - g_free(pvt->bg_file); - pvt->bg_file = NULL; - - g_object_notify(object, "background-image-file"); - } - - /* Set the new background. */ - pvt->bg_pixbuf = image; - - g_object_notify(object, "background-image-pixbuf"); - - vte_terminal_queue_background_update(terminal); - - g_object_thaw_notify(object); -} - -/** - * vte_terminal_set_background_image_file: - * @terminal: a #VteTerminal - * @path: (type filename): path to an image file - * - * Sets a background image for the widget. If specified by - * vte_terminal_set_background_saturation(), the terminal will tint its - * in-memory copy of the image before applying it to the terminal. - */ -void -vte_terminal_set_background_image_file(VteTerminal *terminal, const char *path) -{ - VteTerminalPrivate *pvt; - GObject *object; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - - object = G_OBJECT(terminal); - pvt = terminal->pvt; - - _vte_debug_print(VTE_DEBUG_MISC, - "Loading background image from `%s'.\n", path); - - g_object_freeze_notify(G_OBJECT(terminal)); - - /* Save this background type. */ - g_free(pvt->bg_file); - pvt->bg_file = g_strdup(path); - - /* Turn off other background types. */ - if (pvt->bg_pixbuf != NULL) { - g_object_unref(pvt->bg_pixbuf); - pvt->bg_pixbuf = NULL; - - g_object_notify(object, "background-image-pixbuf"); - } - - g_object_notify(object, "background-image-file"); - - vte_terminal_queue_background_update(terminal); - - g_object_thaw_notify(G_OBJECT(terminal)); } /** @@ -13714,26 +12459,6 @@ vte_terminal_get_has_selection(VteTerminal *terminal) return terminal->pvt->has_selection; } -/** - * vte_terminal_get_using_xft: - * @terminal: a #VteTerminal - * - * A #VteTerminal can use multiple methods to draw text. This function - * allows an application to determine whether or not the current method uses - * fontconfig to find fonts. This setting cannot be changed by the caller, - * but in practice usually matches the behavior of GTK+ itself. - * - * Returns: %TRUE - * - * Deprecated: 0.20 - */ -gboolean -vte_terminal_get_using_xft(VteTerminal *terminal) -{ - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), TRUE); - return TRUE; -} - static void vte_terminal_set_cursor_blinks_internal(VteTerminal *terminal, gboolean blink) { @@ -13748,24 +12473,9 @@ vte_terminal_set_cursor_blinks_internal(VteTerminal *terminal, gboolean blink) } /** - * vte_terminal_set_cursor_blinks: - * @terminal: a #VteTerminal - * @blink: whether the cursor should blink - * - * Sets whether or not the cursor will blink. - * - * Deprecated: 0.17.1 Use vte_terminal_set_cursor_blink_mode() instead. - */ -void -vte_terminal_set_cursor_blinks(VteTerminal *terminal, gboolean blink) -{ - vte_terminal_set_cursor_blink_mode(terminal, blink ? VTE_CURSOR_BLINK_ON : VTE_CURSOR_BLINK_OFF); -} - -/** * vte_terminal_set_cursor_blink_mode: * @terminal: a #VteTerminal - * @mode: the #VteTerminalCursorBlinkMode to use + * @mode: the #VteCursorBlinkMode to use * * Sets whether or not the cursor will blink. Using %VTE_CURSOR_BLINK_SYSTEM * will use the #GtkSettings::gtk-cursor-blink setting. @@ -13773,7 +12483,7 @@ vte_terminal_set_cursor_blinks(VteTerminal *terminal, gboolean blink) * Since: 0.17.1 */ void -vte_terminal_set_cursor_blink_mode(VteTerminal *terminal, VteTerminalCursorBlinkMode mode) +vte_terminal_set_cursor_blink_mode(VteTerminal *terminal, VteCursorBlinkMode mode) { VteTerminalPrivate *pvt; gboolean blinks; @@ -13815,7 +12525,7 @@ vte_terminal_set_cursor_blink_mode(VteTerminal *terminal, VteTerminalCursorBlink * * Since: 0.17.1 */ -VteTerminalCursorBlinkMode +VteCursorBlinkMode vte_terminal_get_cursor_blink_mode(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), VTE_CURSOR_BLINK_SYSTEM); @@ -13826,14 +12536,14 @@ vte_terminal_get_cursor_blink_mode(VteTerminal *terminal) /** * vte_terminal_set_cursor_shape: * @terminal: a #VteTerminal - * @shape: the #VteTerminalCursorShape to use + * @shape: the #VteCursorShape to use * * Sets the shape of the cursor drawn. * * Since: 0.20 */ void -vte_terminal_set_cursor_shape(VteTerminal *terminal, VteTerminalCursorShape shape) +vte_terminal_set_cursor_shape(VteTerminal *terminal, VteCursorShape shape) { VteTerminalPrivate *pvt; @@ -13859,7 +12569,7 @@ vte_terminal_set_cursor_shape(VteTerminal *terminal, VteTerminalCursorShape shap * * Since: 0.17.6 */ -VteTerminalCursorShape +VteCursorShape vte_terminal_get_cursor_shape(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), VTE_CURSOR_SHAPE_BLOCK); @@ -13919,28 +12629,31 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, glong lines) if (screen == &terminal->pvt->normal_screen) { glong low, high, next; /* We need at least as many lines as are visible */ - lines = MAX (lines, terminal->row_count); + lines = MAX (lines, terminal->pvt->row_count); next = MAX (screen->cursor_current.row + 1, _vte_ring_next (screen->row_data)); _vte_ring_resize (screen->row_data, lines); low = _vte_ring_delta (screen->row_data); - high = lines + MIN (G_MAXLONG - lines, low - terminal->row_count + 1); + high = lines + MIN (G_MAXLONG - lines, low - terminal->pvt->row_count + 1); screen->insert_delta = CLAMP (screen->insert_delta, low, high); scroll_delta = CLAMP (scroll_delta, low, screen->insert_delta); - next = MIN (next, screen->insert_delta + terminal->row_count); + next = MIN (next, screen->insert_delta + terminal->pvt->row_count); if (_vte_ring_next (screen->row_data) > next){ _vte_ring_shrink (screen->row_data, next - low); } } else { - _vte_ring_resize (screen->row_data, terminal->row_count); + _vte_ring_resize (screen->row_data, terminal->pvt->row_count); scroll_delta = _vte_ring_delta (screen->row_data); screen->insert_delta = _vte_ring_delta (screen->row_data); - if (_vte_ring_next (screen->row_data) > screen->insert_delta + terminal->row_count){ - _vte_ring_shrink (screen->row_data, terminal->row_count); + if (_vte_ring_next (screen->row_data) > screen->insert_delta + terminal->pvt->row_count){ + _vte_ring_shrink (screen->row_data, terminal->pvt->row_count); } } /* Adjust the scrollbars to the new locations. */ + /* Hack: force a change in scroll_delta even if the value remains, so that + vte_term_q_adj_val_changed() doesn't shortcut to no-op, see bug 676075. */ + terminal->pvt->screen->scroll_delta = -1; vte_terminal_queue_adjustment_value_changed (terminal, scroll_delta); _vte_terminal_adjust_adjustments_full (terminal); @@ -13950,102 +12663,9 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, glong lines) } /** - * vte_terminal_set_word_chars: - * @terminal: a #VteTerminal - * @spec: a specification - * - * When the user double-clicks to start selection, the terminal will extend - * the selection on word boundaries. It will treat characters included in @spec - * as parts of words, and all other characters as word separators. Ranges of - * 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 non-space characters as word characters. - */ -void -vte_terminal_set_word_chars(VteTerminal *terminal, const char *spec) -{ - VteConv conv; - gunichar *wbuf; - guchar *ibuf, *ibufptr, *obuf, *obufptr; - gsize ilen, olen; - VteWordCharRange range; - guint i; - - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - /* Allocate a new range array. */ - if (terminal->pvt->word_chars != NULL) { - g_array_free(terminal->pvt->word_chars, TRUE); - } - terminal->pvt->word_chars = g_array_new(FALSE, TRUE, - sizeof(VteWordCharRange)); - /* Special case: if spec is NULL, try to do the right thing. */ - if (spec == NULL || spec[0] == '\0') { - g_object_notify(G_OBJECT(terminal), "word-chars"); - return; - } - /* Convert the spec from UTF-8 to a string of gunichars . */ - /* FIXME: why not just directly use g_utf8_to_ucs4 here? It'll never fail */ - conv = _vte_conv_open(VTE_CONV_GUNICHAR_TYPE, "UTF-8"); - if (conv == VTE_INVALID_CONV) { - /* Aaargh. We're screwed. */ - g_warning(_("_vte_conv_open() failed setting word characters")); - return; - } - ilen = strlen(spec); - ibuf = ibufptr = (guchar *)g_strdup(spec); - olen = (ilen + 1) * sizeof(gunichar); - _vte_buffer_set_minimum_size(terminal->pvt->conv_buffer, olen); - obuf = obufptr = terminal->pvt->conv_buffer->data; - wbuf = (gunichar*) obuf; - wbuf[ilen] = '\0'; - _vte_conv(conv, (const guchar **)&ibuf, &ilen, &obuf, &olen); - _vte_conv_close(conv); - for (i = 0; i < ((obuf - obufptr) / sizeof(gunichar)); i++) { - /* The hyphen character. */ - if (wbuf[i] == '-') { - range.start = wbuf[i]; - range.end = wbuf[i]; - g_array_append_val(terminal->pvt->word_chars, range); - _vte_debug_print(VTE_DEBUG_MISC, - "Word charset includes hyphen.\n"); - continue; - } - /* A single character, not the start of a range. */ - if ((wbuf[i] != '-') && (wbuf[i + 1] != '-')) { - range.start = wbuf[i]; - range.end = wbuf[i]; - g_array_append_val(terminal->pvt->word_chars, range); - _vte_debug_print(VTE_DEBUG_MISC, - "Word charset includes `%lc'.\n", - (wint_t) wbuf[i]); - continue; - } - /* The start of a range. */ - if ((wbuf[i] != '-') && - (wbuf[i + 1] == '-') && - (wbuf[i + 2] != '-') && - (wbuf[i + 2] != 0)) { - range.start = wbuf[i]; - range.end = wbuf[i + 2]; - g_array_append_val(terminal->pvt->word_chars, range); - _vte_debug_print(VTE_DEBUG_MISC, - "Word charset includes range from " - "`%lc' to `%lc'.\n", (wint_t) wbuf[i], - (wint_t) wbuf[i + 2]); - i += 2; - continue; - } - } - g_free(ibufptr); - - g_object_notify(G_OBJECT(terminal), "word-chars"); -} - -/** * vte_terminal_set_backspace_binding: * @terminal: a #VteTerminal - * @binding: a #VteTerminalEraseBinding for the backspace key + * @binding: a #VteEraseBinding for the backspace key * * Modifies the terminal's backspace key binding, which controls what * string or control sequence the terminal sends to its child when the user @@ -14053,7 +12673,7 @@ vte_terminal_set_word_chars(VteTerminal *terminal, const char *spec) */ void vte_terminal_set_backspace_binding(VteTerminal *terminal, - VteTerminalEraseBinding binding) + VteEraseBinding binding) { VteTerminalPrivate *pvt; @@ -14073,7 +12693,7 @@ vte_terminal_set_backspace_binding(VteTerminal *terminal, /** * vte_terminal_set_delete_binding: * @terminal: a #VteTerminal - * @binding: a #VteTerminalEraseBinding for the delete key + * @binding: a #VteEraseBinding for the delete key * * Modifies the terminal's delete key binding, which controls what * string or control sequence the terminal sends to its child when the user @@ -14081,7 +12701,7 @@ vte_terminal_set_backspace_binding(VteTerminal *terminal, */ void vte_terminal_set_delete_binding(VteTerminal *terminal, - VteTerminalEraseBinding binding) + VteEraseBinding binding) { VteTerminalPrivate *pvt; @@ -14161,6 +12781,7 @@ vte_terminal_reset(VteTerminal *terminal, gboolean clear_history) { VteTerminalPrivate *pvt; + int i; VteSelection sel; g_return_if_fail(VTE_IS_TERMINAL(terminal)); @@ -14176,10 +12797,11 @@ vte_terminal_reset(VteTerminal *terminal, _vte_incoming_chunks_release (pvt->incoming); pvt->incoming = NULL; g_array_set_size(pvt->pending, 0); - _vte_buffer_clear(pvt->outgoing); + _vte_byte_array_clear(pvt->outgoing); /* Reset charset substitution state. */ _vte_iso2022_state_free(pvt->iso2022); pvt->iso2022 = _vte_iso2022_state_new(NULL, + pvt->iso2022_utf8_ambiguous_width, &_vte_terminal_codeset_changed_cb, terminal); _vte_iso2022_state_set_codeset(pvt->iso2022, @@ -14193,19 +12815,21 @@ vte_terminal_reset(VteTerminal *terminal, pvt->vt220_fkey_mode = FALSE; /* Enable meta-sends-escape. */ pvt->meta_sends_escape = TRUE; - /* Disable smooth scroll. */ - pvt->smooth_scroll = FALSE; /* Disable margin bell. */ pvt->margin_bell = FALSE; /* Enable iso2022/NRC processing. */ pvt->nrc_mode = TRUE; + /* Disable DECCOLM mode. */ + pvt->deccolm_mode = FALSE; /* Reset saved settings. */ if (pvt->dec_saved != NULL) { g_hash_table_destroy(pvt->dec_saved); pvt->dec_saved = g_hash_table_new(NULL, NULL); } - /* Reset the color palette. */ - /* vte_terminal_set_default_colors(terminal); */ + /* Reset the color palette. Only the 256 indexed colors, not the special ones. + * (XTerm doesn't reset the cursor color, the others are not alterable by escapes in vte.) */ + for (i = 0; i < 256; i++) + terminal->pvt->palette[i].sources[VTE_COLOR_SOURCE_ESCAPE].is_set = FALSE; /* Reset the default attributes. Reset the alternate attribute because * it's not a real attribute, but we need to treat it as one here. */ pvt->screen = &pvt->alternate_screen; @@ -14220,7 +12844,7 @@ vte_terminal_reset(VteTerminal *terminal, _vte_ring_fini(pvt->normal_screen.row_data); _vte_ring_init(pvt->normal_screen.row_data, pvt->scrollback_lines); _vte_ring_fini(pvt->alternate_screen.row_data); - _vte_ring_init(pvt->alternate_screen.row_data, terminal->row_count); + _vte_ring_init(pvt->alternate_screen.row_data, terminal->pvt->row_count); pvt->normal_screen.cursor_saved.row = 0; pvt->normal_screen.cursor_saved.col = 0; pvt->normal_screen.cursor_current.row = 0; @@ -14271,6 +12895,8 @@ vte_terminal_reset(VteTerminal *terminal, pvt->alternate_screen.reverse_mode = FALSE; pvt->alternate_screen.bracketed_paste_mode = FALSE; pvt->cursor_visible = TRUE; + /* For some reason, xterm doesn't reset alternateScroll, but we do. */ + pvt->alternate_screen_scroll = TRUE; /* Reset the encoding. */ vte_terminal_set_encoding(terminal, NULL); g_assert(pvt->encoding != NULL); @@ -14288,19 +12914,23 @@ vte_terminal_reset(VteTerminal *terminal, pvt->selection_html[sel] = NULL; } } - memset(&pvt->selection_origin, 0, - sizeof(&pvt->selection_origin)); - memset(&pvt->selection_last, 0, - sizeof(&pvt->selection_last)); - memset(&pvt->selection_start, 0, - sizeof(&pvt->selection_start)); - memset(&pvt->selection_end, 0, - sizeof(&pvt->selection_end)); + memset(&pvt->selection_origin, 0, + sizeof(pvt->selection_origin)); + memset(&pvt->selection_last, 0, + sizeof(pvt->selection_last)); + memset(&pvt->selection_start, 0, + sizeof(pvt->selection_start)); + memset(&pvt->selection_end, 0, + sizeof(pvt->selection_end)); + /* Reset mouse motion events. */ pvt->mouse_tracking_mode = MOUSE_TRACKING_NONE; pvt->mouse_last_button = 0; pvt->mouse_last_x = 0; pvt->mouse_last_y = 0; + pvt->mouse_xterm_extension = FALSE; + pvt->mouse_urxvt_extension = FALSE; + pvt->mouse_smooth_scroll_delta = 0.; /* Clear modifiers. */ pvt->modifiers = 0; /* Cause everything to be redrawn (or cleared). */ @@ -14330,51 +12960,6 @@ vte_terminal_get_status_line(VteTerminal *terminal) } /** - * vte_terminal_get_padding: - * @terminal: a #VteTerminal - * @xpad: address in which to store left/right-edge padding - * @ypad: address in which to store top/bottom-edge ypadding - * - * Determines the amount of additional space the widget is using to pad the - * edges of its visible area. This is necessary for cases where characters in - * the selected font don't themselves include a padding area and the text - * itself would otherwise be contiguous with the window border. Applications - * which use the widget's %row_count, %column_count, %char_height, and - * %char_width fields to set geometry hints using - * gtk_window_set_geometry_hints() will need to add this value to the base - * size. The values returned in @xpad and @ypad are the total padding used in - * each direction, and do not need to be doubled. - * - * Deprecated: 0.26: Get the #VteTerminal:inner-border style property instead - */ -void -vte_terminal_get_padding(VteTerminal *terminal, int *xpad, int *ypad) -{ - g_return_if_fail(VTE_IS_TERMINAL(terminal)); - g_return_if_fail(xpad != NULL); - g_return_if_fail(ypad != NULL); - *xpad = terminal->pvt->inner_border.left + terminal->pvt->inner_border.right; - *ypad = terminal->pvt->inner_border.top + terminal->pvt->inner_border.bottom; -} - -/** - * vte_terminal_get_adjustment: - * @terminal: a #VteTerminal - * - * An accessor function provided for the benefit of language bindings. - * - * Returns: (transfer none): the contents of @terminal's adjustment field - * - * Deprecated: 0.28: Use gtk_scrollable_get_vadjustment() instead - */ -GtkAdjustment * -vte_terminal_get_adjustment(VteTerminal *terminal) -{ - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); - return terminal->adjustment; -} - -/** * vte_terminal_get_char_width: * @terminal: a #VteTerminal * @@ -14385,7 +12970,7 @@ vte_terminal_get_char_width(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); vte_terminal_ensure_font (terminal); - return terminal->char_width; + return terminal->pvt->char_width; } /** @@ -14399,43 +12984,7 @@ vte_terminal_get_char_height(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); vte_terminal_ensure_font (terminal); - return terminal->char_height; -} - -/** - * vte_terminal_get_char_descent: - * @terminal: a #VteTerminal - * - * An accessor function provided for the benefit of language bindings. - * - * Returns: the contents of @terminal's char_descent field - * - * Deprecated: 0.20 - */ -glong -vte_terminal_get_char_descent(VteTerminal *terminal) -{ - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - vte_terminal_ensure_font (terminal); - return terminal->char_descent; -} - -/** - * vte_terminal_get_char_ascent: - * @terminal: a #VteTerminal - * - * An accessor function provided for the benefit of language bindings. - * - * Returns: the contents of @terminal's char_ascent field - * - * Deprecated: 0.20 - */ -glong -vte_terminal_get_char_ascent(VteTerminal *terminal) -{ - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - vte_terminal_ensure_font (terminal); - return terminal->char_ascent; + return terminal->pvt->char_height; } /** @@ -14449,7 +12998,7 @@ glong vte_terminal_get_row_count(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - return terminal->row_count; + return terminal->pvt->row_count; } /** @@ -14462,7 +13011,7 @@ glong vte_terminal_get_column_count(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - return terminal->column_count; + return terminal->pvt->column_count; } /** @@ -14475,7 +13024,7 @@ const char * vte_terminal_get_window_title(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), ""); - return terminal->window_title; + return terminal->pvt->window_title; } /** @@ -14488,41 +13037,44 @@ const char * vte_terminal_get_icon_title(VteTerminal *terminal) { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), ""); - return terminal->icon_title; + return terminal->pvt->icon_title; } /** - * vte_terminal_set_pty: + * vte_terminal_get_current_directory_uri: * @terminal: a #VteTerminal - * @pty_master: a file descriptor of the master end of a PTY, or %-1 - * - * Attach an existing PTY master side to the terminal widget. Use - * instead of vte_terminal_fork_command() or vte_terminal_forkpty(). * - * Since: 0.12.1 + * Returns: (transfer none): the URI of the current directory of the + * process running in the terminal, or %NULL * - * Deprecated: 0.26: Use vte_pty_new_foreign() and vte_terminal_set_pty_object() + * Since: 0.34 */ -void -vte_terminal_set_pty(VteTerminal *terminal, int pty_master) +const char * +vte_terminal_get_current_directory_uri(VteTerminal *terminal) { - VtePty *pty; - - if (pty_master == -1) { - vte_terminal_set_pty_object(terminal, NULL); - return; - } - - pty = vte_pty_new_foreign(pty_master, NULL); - if (pty == NULL) - return; + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); + return terminal->pvt->current_directory_uri; +} - vte_terminal_set_pty_object(terminal, pty); - g_object_unref(pty); +/** + * vte_terminal_get_current_file_uri: + * @terminal: a #VteTerminal + * + * Returns: (transfer none): the URI of the current file the + * process running in the terminal is operating on, or %NULL if + * not set + * + * Since: 0.34 + */ +const char * +vte_terminal_get_current_file_uri(VteTerminal *terminal) +{ + g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); + return terminal->pvt->current_file_uri; } /** - * vte_terminal_set_pty_object: + * vte_terminal_set_pty: * @terminal: a #VteTerminal * @pty: (allow-none): a #VtePty, or %NULL * @@ -14532,7 +13084,7 @@ vte_terminal_set_pty(VteTerminal *terminal, int pty_master) * Since: 0.26. */ void -vte_terminal_set_pty_object(VteTerminal *terminal, +vte_terminal_set_pty(VteTerminal *terminal, VtePty *pty) { VteTerminalPrivate *pvt; @@ -14573,7 +13125,7 @@ vte_terminal_set_pty_object(VteTerminal *terminal, vte_terminal_stop_processing (terminal); /* Clear the outgoing buffer as well. */ - _vte_buffer_clear(terminal->pvt->outgoing); + _vte_byte_array_clear(terminal->pvt->outgoing); vte_pty_close(pvt->pty); g_object_unref(pvt->pty); @@ -14583,7 +13135,6 @@ vte_terminal_set_pty_object(VteTerminal *terminal, if (pty == NULL) { pvt->pty = NULL; g_object_notify(object, "pty"); - g_object_notify(object, "pty-object"); g_object_thaw_notify(object); return; } @@ -14602,8 +13153,8 @@ vte_terminal_set_pty_object(VteTerminal *terminal, } vte_terminal_set_size(terminal, - terminal->column_count, - terminal->row_count); + terminal->pvt->column_count, + terminal->pvt->row_count); _vte_terminal_setup_utf8 (terminal); @@ -14611,7 +13162,6 @@ vte_terminal_set_pty_object(VteTerminal *terminal, _vte_terminal_connect_pty_read (terminal); g_object_notify(object, "pty"); - g_object_notify(object, "pty-object"); g_object_thaw_notify(object); } @@ -14620,32 +13170,6 @@ vte_terminal_set_pty_object(VteTerminal *terminal, * vte_terminal_get_pty: * @terminal: a #VteTerminal * - * Returns the file descriptor of the master end of @terminal's PTY. - * - * Return value: the file descriptor, or -1 if the terminal has no PTY. - * - * Since: 0.20 - * - * Deprecated: 0.26: Use vte_terminal_get_pty_object() and vte_pty_get_fd() - */ -int -vte_terminal_get_pty(VteTerminal *terminal) -{ - VteTerminalPrivate *pvt; - - g_return_val_if_fail (VTE_IS_TERMINAL (terminal), -1); - - pvt = terminal->pvt; - if (pvt->pty != NULL) - return vte_pty_get_fd(pvt->pty); - - return -1; -} - -/** - * vte_terminal_get_pty_object: - * @terminal: a #VteTerminal - * * Returns the #VtePty of @terminal. * * Returns: (transfer none): a #VtePty, or %NULL @@ -14653,35 +13177,13 @@ vte_terminal_get_pty(VteTerminal *terminal) * Since: 0.26 */ VtePty * -vte_terminal_get_pty_object(VteTerminal *terminal) +vte_terminal_get_pty(VteTerminal *terminal) { g_return_val_if_fail (VTE_IS_TERMINAL (terminal), NULL); return terminal->pvt->pty; } -/** - * vte_terminal_get_child_exit_status: - * @terminal: a #VteTerminal - * - * Gets the exit status of the command started by vte_terminal_fork_command(). - * See your C library's documentation for more details on how to interpret the - * exit status. - * - * Note that this function may only be called from the signal handler of - * the #VteTerminal::child-exited signal. - * - * Returns: the child's exit status - * - * Since: 0.20 - */ -int -vte_terminal_get_child_exit_status(VteTerminal *terminal) -{ - g_return_val_if_fail(VTE_IS_TERMINAL(terminal), -1); - return terminal->pvt->child_exit_status; -} - /* We need this bit of glue to ensure that accessible objects will always * get signals. */ void @@ -14806,7 +13308,7 @@ reset_update_regions (VteTerminal *terminal) { if (terminal->pvt->update_regions != NULL) { g_slist_foreach (terminal->pvt->update_regions, - (GFunc)gdk_region_destroy, NULL); + (GFunc)cairo_region_destroy, NULL); g_slist_free (terminal->pvt->update_regions); terminal->pvt->update_regions = NULL; } @@ -14912,6 +13414,22 @@ vte_terminal_emit_window_title_changed(VteTerminal *terminal) } static void +vte_terminal_emit_current_directory_uri_changed(VteTerminal *terminal) +{ + _vte_debug_print(VTE_DEBUG_SIGNALS, + "Emitting `current-directory-uri-changed'.\n"); + g_signal_emit_by_name(terminal, "current-directory-uri-changed"); +} + +static void +vte_terminal_emit_current_file_uri_changed(VteTerminal *terminal) +{ + _vte_debug_print(VTE_DEBUG_SIGNALS, + "Emitting `current-file-uri-changed'.\n"); + g_signal_emit_by_name(terminal, "current-file-uri-changed"); +} + +static void vte_terminal_emit_pending_signals(VteTerminal *terminal) { GObject *object; @@ -14930,27 +13448,45 @@ vte_terminal_emit_pending_signals(VteTerminal *terminal) } if (terminal->pvt->window_title_changed) { - g_free (terminal->window_title); - terminal->window_title = terminal->pvt->window_title_changed; + g_free (terminal->pvt->window_title); + terminal->pvt->window_title = terminal->pvt->window_title_changed; terminal->pvt->window_title_changed = NULL; if (window) - gdk_window_set_title (window, terminal->window_title); + gdk_window_set_title (window, terminal->pvt->window_title); vte_terminal_emit_window_title_changed(terminal); g_object_notify(object, "window-title"); } if (terminal->pvt->icon_title_changed) { - g_free (terminal->icon_title); - terminal->icon_title = terminal->pvt->icon_title_changed; + g_free (terminal->pvt->icon_title); + terminal->pvt->icon_title = terminal->pvt->icon_title_changed; terminal->pvt->icon_title_changed = NULL; if (window) - gdk_window_set_icon_name (window, terminal->icon_title); + gdk_window_set_icon_name (window, terminal->pvt->icon_title); vte_terminal_emit_icon_title_changed(terminal); g_object_notify(object, "icon-title"); } + if (terminal->pvt->current_directory_uri_changed) { + g_free (terminal->pvt->current_directory_uri); + terminal->pvt->current_directory_uri = terminal->pvt->current_directory_uri_changed; + terminal->pvt->current_directory_uri_changed = NULL; + + vte_terminal_emit_current_directory_uri_changed(terminal); + g_object_notify(object, "current-directory-uri"); + } + + if (terminal->pvt->current_file_uri_changed) { + g_free (terminal->pvt->current_file_uri); + terminal->pvt->current_file_uri = terminal->pvt->current_file_uri_changed; + terminal->pvt->current_file_uri_changed = NULL; + + vte_terminal_emit_current_file_uri_changed(terminal); + g_object_notify(object, "current-file-uri"); + } + /* Flush any pending "inserted" signals. */ vte_terminal_emit_cursor_moved(terminal); vte_terminal_emit_pending_text_signals(terminal, 0); @@ -14981,7 +13517,9 @@ process_timeout (gpointer data) GList *l, *next; gboolean again; - GDK_THREADS_ENTER(); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_enter(); + G_GNUC_END_IGNORE_DEPRECATIONS; in_process_timeout = TRUE; @@ -15043,7 +13581,9 @@ process_timeout (gpointer data) in_process_timeout = FALSE; - GDK_THREADS_LEAVE(); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_leave(); + G_GNUC_END_IGNORE_DEPRECATIONS; if (again) { /* Force us to relinquish the CPU as the child is running @@ -15063,11 +13603,12 @@ static gboolean update_regions (VteTerminal *terminal) { GSList *l; - GdkRegion *region; + cairo_region_t *region; GdkWindow *window; - if (G_UNLIKELY (! gtk_widget_is_drawable (&terminal->widget) - || terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED)) { + if (G_UNLIKELY(!gtk_widget_get_realized(&terminal->widget))) + return FALSE; + if (terminal->pvt->visibility_state == GDK_VISIBILITY_FULLY_OBSCURED) { reset_update_regions (terminal); return FALSE; } @@ -15079,10 +13620,10 @@ update_regions (VteTerminal *terminal) l = terminal->pvt->update_regions; if (g_slist_next (l) != NULL) { /* amalgamate into one super-region */ - region = gdk_region_new (); + region = cairo_region_create (); do { - gdk_region_union (region, l->data); - gdk_region_destroy (l->data); + cairo_region_union (region, l->data); + cairo_region_destroy (l->data); } while ((l = g_slist_next (l)) != NULL); } else { region = l->data; @@ -15095,7 +13636,7 @@ update_regions (VteTerminal *terminal) window = gtk_widget_get_window (&terminal->widget); gdk_window_invalidate_region (window, region, FALSE); gdk_window_process_updates (window, FALSE); - gdk_region_destroy (region); + cairo_region_destroy (region); _vte_debug_print (VTE_DEBUG_WORK, "-"); @@ -15108,7 +13649,9 @@ update_repeat_timeout (gpointer data) GList *l, *next; gboolean again; - GDK_THREADS_ENTER(); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_enter(); + G_GNUC_END_IGNORE_DEPRECATIONS; in_update_timeout = TRUE; @@ -15134,9 +13677,6 @@ update_repeat_timeout (gpointer data) } _vte_terminal_enable_input_source (terminal); } - if (terminal->pvt->bg_update_pending) { - vte_terminal_background_update (terminal); - } vte_terminal_emit_adjustment_changed (terminal); if (need_processing (terminal)) { if (VTE_MAX_PROCESS_TIME) { @@ -15184,7 +13724,9 @@ update_repeat_timeout (gpointer data) in_update_timeout = FALSE; - GDK_THREADS_LEAVE(); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_leave(); + G_GNUC_END_IGNORE_DEPRECATIONS; if (again) { /* Force us to relinquish the CPU as the child is running @@ -15205,7 +13747,9 @@ update_timeout (gpointer data) GList *l, *next; gboolean redraw = FALSE; - GDK_THREADS_ENTER(); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_enter(); + G_GNUC_END_IGNORE_DEPRECATIONS; in_update_timeout = TRUE; @@ -15238,9 +13782,6 @@ update_timeout (gpointer data) } _vte_terminal_enable_input_source (terminal); } - if (terminal->pvt->bg_update_pending) { - vte_terminal_background_update (terminal); - } vte_terminal_emit_adjustment_changed (terminal); if (need_processing (terminal)) { if (VTE_MAX_PROCESS_TIME) { @@ -15273,7 +13814,9 @@ update_timeout (gpointer data) NULL); in_update_timeout = FALSE; - GDK_THREADS_LEAVE(); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gdk_threads_leave(); + G_GNUC_END_IGNORE_DEPRECATIONS; return FALSE; } @@ -15282,7 +13825,7 @@ update_timeout (gpointer data) * vte_terminal_write_contents: * @terminal: a #VteTerminal * @stream: a #GOutputStream to write to - * @flags: a set of #VteTerminalWriteFlags + * @flags: a set of #VteWriteFlags * @cancellable: (allow-none): a #GCancellable object, or %NULL * @error: (allow-none): a #GError location to store the error occuring, or %NULL * @@ -15304,7 +13847,7 @@ update_timeout (gpointer data) gboolean vte_terminal_write_contents (VteTerminal *terminal, GOutputStream *stream, - VteTerminalWriteFlags flags, + VteWriteFlags flags, GCancellable *cancellable, GError **error) { @@ -15326,6 +13869,7 @@ vte_terminal_write_contents (VteTerminal *terminal, * vte_terminal_search_set_gregex: * @terminal: a #VteTerminal * @regex: (allow-none): a #GRegex, or %NULL + * @flags: flags from #GRegexMatchFlags * * Sets the #GRegex regex to search for. Unsets the search regex when passed %NULL. * @@ -15333,7 +13877,8 @@ vte_terminal_write_contents (VteTerminal *terminal, */ void vte_terminal_search_set_gregex (VteTerminal *terminal, - GRegex *regex) + GRegex *regex, + GRegexMatchFlags flags) { g_return_if_fail(VTE_IS_TERMINAL(terminal)); @@ -15347,6 +13892,7 @@ vte_terminal_search_set_gregex (VteTerminal *terminal, if (regex) terminal->pvt->search_regex = g_regex_ref (regex); + terminal->pvt->search_match_flags = flags; _vte_invalidate_all (terminal); } @@ -15423,7 +13969,9 @@ vte_terminal_search_rows (VteTerminal *terminal, row_text = vte_terminal_get_text_range (terminal, start_row, 0, end_row, -1, NULL, NULL, NULL); - g_regex_match_full (pvt->search_regex, row_text, -1, 0, G_REGEX_MATCH_NOTEMPTY, &match_info, &error); + g_regex_match_full (pvt->search_regex, row_text, -1, 0, + pvt->search_match_flags | G_REGEX_MATCH_NOTEMPTY, + &match_info, &error); if (error) { g_printerr ("Error while matching: %s\n", error->message); g_error_free (error); @@ -15463,8 +14011,8 @@ vte_terminal_search_rows (VteTerminal *terminal, _vte_terminal_select_text (terminal, start_col, start_row, end_col, end_row, 0, 0); /* Quite possibly the math here should not access adjustment directly... */ - value = gtk_adjustment_get_value(terminal->adjustment); - page_size = gtk_adjustment_get_page_size(terminal->adjustment); + value = gtk_adjustment_get_value(terminal->pvt->vadjustment); + page_size = gtk_adjustment_get_page_size(terminal->pvt->vadjustment); if (backward) { if (end_row < value || end_row >= value + page_size) vte_terminal_queue_adjustment_value_changed_clamped (terminal, end_row - page_size + 1); @@ -15542,7 +14090,7 @@ vte_terminal_search_find (VteTerminal *terminal, last_start_row = pvt->selection_start.row; last_end_row = pvt->selection_end.row + 1; } else { - last_start_row = pvt->screen->scroll_delta + terminal->row_count; + last_start_row = pvt->screen->scroll_delta + terminal->pvt->row_count; last_end_row = pvt->screen->scroll_delta; } last_start_row = MAX (buffer_start_row, last_start_row); @@ -15620,3 +14168,79 @@ vte_terminal_search_find_next (VteTerminal *terminal) { return vte_terminal_search_find (terminal, FALSE); } + +/* Just some arbitrary minimum values */ +#define MIN_COLUMNS (16) +#define MIN_ROWS (2) + +/** + * vte_terminal_get_geometry_hints: + * @terminal: a #VteTerminal + * @hints: (out caller-allocates): a #GdkGeometry to fill in + * @min_rows: the minimum number of rows to request + * @min_columns: the minimum number of columns to request + * + * Fills in some @hints from @terminal's geometry. The hints + * filled are those covered by the %GDK_HINT_RESIZE_INC, + * %GDK_HINT_MIN_SIZE and %GDK_HINT_BASE_SIZE flags. + * + * See gtk_window_set_geometry_hints() for more information. + * + * @terminal must be realized (see gtk_widget_get_realized()). + */ +void +vte_terminal_get_geometry_hints(VteTerminal *terminal, + GdkGeometry *hints, + int min_rows, + int min_columns) +{ + VteTerminalPrivate *pvt; + GtkWidget *widget; + GtkBorder padding; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(hints != NULL); + widget = &terminal->widget; + g_return_if_fail(gtk_widget_get_realized(widget)); + + pvt = terminal->pvt; + + gtk_style_context_get_padding(gtk_widget_get_style_context(widget), + gtk_widget_get_state_flags(widget), + &padding); + + hints->base_width = padding.left + padding.right; + hints->base_height = padding.top + padding.bottom; + hints->width_inc = pvt->char_width; + hints->height_inc = pvt->char_height; + hints->min_width = hints->base_width + hints->width_inc * min_columns; + hints->min_height = hints->base_height + hints->height_inc * min_rows; +} + +/** + * vte_terminal_set_geometry_hints_for_window: + * @terminal: a #VteTerminal + * @window: a #GtkWindow + * + * Sets @terminal as @window's geometry widget. See + * gtk_window_set_geometry_hints() for more information. + * + * @terminal must be realized (see gtk_widget_get_realized()). + */ +void +vte_terminal_set_geometry_hints_for_window(VteTerminal *terminal, + GtkWindow *window) +{ + GdkGeometry hints; + + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(gtk_widget_get_realized(&terminal->widget)); + + vte_terminal_get_geometry_hints(terminal, &hints, MIN_ROWS, MIN_COLUMNS); + gtk_window_set_geometry_hints(window, + &terminal->widget, + &hints, + GDK_HINT_RESIZE_INC | + GDK_HINT_MIN_SIZE | + GDK_HINT_BASE_SIZE); +} |