diff options
author | Christian Persch <chpe@src.gnome.org> | 2017-05-07 13:57:41 +0200 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2017-05-07 13:57:41 +0200 |
commit | 91e9c83878ee389ad63f45c7ec654011b75039e5 (patch) | |
tree | 41ffca3c1098308c96d0bd35ad0d4ce787e4e700 | |
parent | 64be114a87ad20e874860a7a819c16fa394c69f8 (diff) | |
download | vte-91e9c83878ee389ad63f45c7ec654011b75039e5.tar.gz |
widget: Provide a way to copy the selection to clipboard as HTML
Currently, copying to HTML is disabled (#if 0) in the code, because
it will generate the potentially huge selection data in both text and
HTML formats.
Instead, provide API to tell vte which format to use.
https://bugzilla.gnome.org/show_bug.cgi?id=365121
-rw-r--r-- | bindings/vala/app.ui | 1 | ||||
-rw-r--r-- | bindings/vala/app.vala | 12 | ||||
-rw-r--r-- | doc/reference/vte-sections.txt | 6 | ||||
-rw-r--r-- | src/vte.cc | 325 | ||||
-rw-r--r-- | src/vte/vtedeprecated.h | 4 | ||||
-rw-r--r-- | src/vte/vteenums.h | 15 | ||||
-rw-r--r-- | src/vte/vteterminal.h | 3 | ||||
-rw-r--r-- | src/vteaccess.cc | 4 | ||||
-rw-r--r-- | src/vtegtk.cc | 71 | ||||
-rw-r--r-- | src/vteinternal.hh | 38 |
10 files changed, 270 insertions, 209 deletions
diff --git a/bindings/vala/app.ui b/bindings/vala/app.ui index 8fb9dbb9..bfcedd5f 100644 --- a/bindings/vala/app.ui +++ b/bindings/vala/app.ui @@ -43,6 +43,7 @@ <property name="receives_default">True</property> <property name="tooltip_text" translatable="yes">Copy</property> <property name="action_name">win.copy</property> + <property name="action_target">"text"</property> <property name="focus_on_click">False</property> <child> <object class="GtkImage" id="image2"> diff --git a/bindings/vala/app.vala b/bindings/vala/app.vala index 11cd1ff8..8663d63c 100644 --- a/bindings/vala/app.vala +++ b/bindings/vala/app.vala @@ -196,7 +196,7 @@ class Window : Gtk.ApplicationWindow }; private const GLib.ActionEntry[] action_entries = { - { "copy", action_copy_cb }, + { "copy", action_copy_cb, "s" }, { "copy-match", action_copy_match_cb, "s" }, { "paste", action_paste_cb }, { "reset", action_reset_cb, "b" }, @@ -564,9 +564,12 @@ class Window : Gtk.ApplicationWindow /* Callbacks */ - private void action_copy_cb() + private void action_copy_cb(GLib.SimpleAction action, GLib.Variant? parameter) { - terminal.copy_clipboard(); + size_t len; + unowned string str = parameter.get_string(out len); + + terminal.copy_clipboard_format(str == "html" ? Vte.Format.HTML : Vte.Format.TEXT); } private void action_copy_match_cb(GLib.SimpleAction action, GLib.Variant? parameter) @@ -625,7 +628,8 @@ class Window : Gtk.ApplicationWindow return false; var menu = new GLib.Menu(); - menu.append("_Copy", "win.copy"); + menu.append("_Copy", "win.copy::text"); + menu.append("Copy As _HTML", "win.copy::html"); #if VALA_0_24 if (event != null) { diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt index 69683dd6..9b34536c 100644 --- a/doc/reference/vte-sections.txt +++ b/doc/reference/vte-sections.txt @@ -5,6 +5,7 @@ VteTerminal VteCursorBlinkMode VteCursorShape VteEraseBinding +VteFormat VteWriteFlags VteSelectionFunc vte_terminal_new @@ -13,7 +14,7 @@ vte_terminal_feed_child vte_terminal_feed_child_binary vte_terminal_select_all vte_terminal_unselect_all -vte_terminal_copy_clipboard +vte_terminal_copy_clipboard_format vte_terminal_paste_clipboard vte_terminal_copy_primary vte_terminal_paste_primary @@ -102,6 +103,8 @@ VTE_TYPE_CURSOR_SHAPE vte_cursor_shape_get_type VTE_TYPE_ERASE_BINDING vte_erase_binding_get_type +VTE_TYPE_FORMAT +vte_format_get_type VTE_TYPE_WRITE_FLAGS vte_write_flags_get_type VTE_TYPE_TERMINAL @@ -123,6 +126,7 @@ vte_terminal_get_current_directory_uri vte_terminal_get_current_file_uri <SUBSECTION Deprecated> +vte_terminal_copy_clipboard vte_terminal_match_set_cursor vte_terminal_match_add_gregex vte_terminal_search_get_gregex @@ -1033,10 +1033,10 @@ VteTerminalPrivate::match_contents_refresh() { match_contents_clear(); GArray *array = g_array_new(FALSE, TRUE, sizeof(struct _VteCharAttributes)); - m_match_contents = get_text_displayed(true /* wrap */, - false /* include trailing whitespace */, - array, - nullptr); + auto match_contents = get_text_displayed(true /* wrap */, + false /* include trailing whitespace */, + array); + m_match_contents = g_string_free(match_contents, FALSE); m_match_attributes = array; } @@ -3845,13 +3845,14 @@ next_match: * by this insertion. */ if (m_has_selection) { //FIXMEchpe: this is atrocious - char *selection = get_selected_text(); - if ((selection == NULL) || - (m_selection_text[VTE_SELECTION_PRIMARY] == NULL) || - (strcmp(selection, m_selection_text[VTE_SELECTION_PRIMARY]) != 0)) { + auto selection = get_selected_text(); + if ((selection == nullptr) || + (m_selection[VTE_SELECTION_PRIMARY] == nullptr) || + (strcmp(selection->str, m_selection[VTE_SELECTION_PRIMARY]->str) != 0)) { deselect_all(); } - g_free(selection); + if (selection) + g_string_free(selection, TRUE); } } @@ -5873,46 +5874,58 @@ clipboard_copy_cb(GtkClipboard *clipboard, that->widget_clipboard_requested(clipboard, data, info); } +static char* +text_to_utf16_mozilla(GString* text, + gsize* len_ptr) +{ + /* Use g_convert() instead of g_utf8_to_utf16() since the former + * adds a BOM which Mozilla requires for text/html format. + */ + return g_convert(text->str, text->len, + "UTF-16", /* conver to UTF-16 */ + "UTF-8", /* convert from UTF-8 */ + nullptr /* out bytes_read */, + len_ptr, + nullptr); +} + void VteTerminalPrivate::widget_clipboard_requested(GtkClipboard *target_clipboard, GtkSelectionData *data, guint info) { - int sel; - - for (sel = 0; sel < LAST_VTE_SELECTION; sel++) { + for (auto sel = 0; sel < LAST_VTE_SELECTION; sel++) { if (target_clipboard == m_clipboard[sel] && - m_selection_text[sel] != nullptr) { + m_selection[sel] != nullptr) { _VTE_DEBUG_IF(VTE_DEBUG_SELECTION) { int i; - g_printerr("Setting selection %d (%" G_GSIZE_FORMAT " UTF-8 bytes.)\n", - sel, - strlen(m_selection_text[sel])); - for (i = 0; m_selection_text[sel][i] != '\0'; i++) { - g_printerr("0x%04x\n", - m_selection_text[sel][i]); + g_printerr("Setting selection %d (%" G_GSIZE_FORMAT " UTF-8 bytes.) for target %s\n", + sel, + m_selection[sel]->len, + gdk_atom_name(gtk_selection_data_get_target(data))); + char const* selection_text = m_selection[sel]->str; + for (i = 0; selection_text[i] != '\0'; i++) { + g_printerr("0x%04x ", selection_text[i]); + if ((i & 0x7) == 0x7) + g_printerr("\n"); } + g_printerr("\n"); } if (info == VTE_TARGET_TEXT) { - // FIXMEchpe cache the strlen instead of passing -1 here, and below - gtk_selection_data_set_text(data, m_selection_text[sel], -1); + gtk_selection_data_set_text(data, + m_selection[sel]->str, + m_selection[sel]->len); } else if (info == VTE_TARGET_HTML) { -#ifdef HTML_SELECTION gsize len; - gchar *selection; - - /* Mozilla asks that we start our text/html with the Unicode byte order mark */ - /* (Comment found in gtkimhtml.c of pidgin fame) */ - selection = g_convert(m_selection_html[sel], - -1, "UTF-16", "UTF-8", NULL, &len, NULL); + auto selection = text_to_utf16_mozilla(m_selection[sel], &len); // FIXMEchpe this makes yet another copy of the data... :( - gtk_selection_data_set(data, - gdk_atom_intern("text/html", FALSE), - 16, - (const guchar *)selection, - len); + if (selection) + gtk_selection_data_set(data, + gdk_atom_intern_static_string("text/html"), + 16, + (const guchar *)selection, + len); g_free(selection); -#endif } else { /* Not reached */ } @@ -5950,26 +5963,6 @@ VteTerminalPrivate::rgb_from_index(guint index, } } -char * -VteTerminalPrivate::get_text(vte::grid::row_t start_row, - vte::grid::column_t start_col, - vte::grid::row_t end_row, - vte::grid::column_t end_col, - bool block, - bool wrap, - bool include_trailing_spaces, - GArray *attributes, - gsize *ret_len) -{ - GString *text = get_text(start_row, start_col, - end_row, end_col, - block, wrap, include_trailing_spaces, - attributes); - if (ret_len) - *ret_len = text->len; - return static_cast<char*>(g_string_free(text, FALSE)); -} - GString* VteTerminalPrivate::get_text(vte::grid::row_t start_row, vte::grid::column_t start_col, @@ -6103,22 +6096,12 @@ VteTerminalPrivate::get_text(vte::grid::row_t start_row, vte_g_array_fill (attributes, &attr, string->len); } } + /* Sanity check. */ - g_assert(attributes == NULL || string->len == attributes->len); - return string; -} + if (attributes != nullptr) + g_assert_cmpuint(string->len, ==, attributes->len); -char * -VteTerminalPrivate::get_text_displayed(bool wrap, - bool include_trailing_spaces, - GArray *attributes, - gsize *ret_len) -{ - GString *text = get_text_displayed(wrap, include_trailing_spaces, - attributes); - if (ret_len) - *ret_len = text->len; - return static_cast<char*>(g_string_free(text, FALSE)); + return string; } GString* @@ -6146,9 +6129,8 @@ VteTerminalPrivate::get_text_displayed_a11y(bool wrap, attributes); } -char * -VteTerminalPrivate::get_selected_text(GArray *attributes, - gsize *len_ptr) +GString* +VteTerminalPrivate::get_selected_text(GArray *attributes) { return get_text(m_selection_start.row, m_selection_start.col, @@ -6157,8 +6139,7 @@ VteTerminalPrivate::get_selected_text(GArray *attributes, m_selection_block_mode, true /* wrap */, false /* include trailing whitespace */, - attributes, - len_ptr); + attributes); } /* @@ -6275,17 +6256,18 @@ VteTerminalPrivate::char_to_cell_attr(VteCharAttributes const* attr) const * * Returns: (transfer full): a newly allocated text string, or %NULL. */ -char * -VteTerminalPrivate::attributes_to_html(char const* text, - gsize len, - GArray *attrs) +GString* +VteTerminalPrivate::attributes_to_html(GString* text_string, + GArray* attrs) { GString *string; guint from,to; const VteCellAttr *attr; char *escaped, *marked; - g_assert(len == attrs->len); + char const* text = text_string->str; + auto len = text_string->len; + g_assert_cmpuint(len, ==, attrs->len); /* Initial size fits perfectly if the text has no attributes and no * characters that need to be escaped @@ -6322,29 +6304,85 @@ VteTerminalPrivate::attributes_to_html(char const* text, } g_string_append(string, "</pre>"); - return g_string_free(string, FALSE); + return string; +} + +static GtkTargetEntry* +targets_for_format(VteFormat format, + int *n_targets) +{ + switch (format) { + case VTE_FORMAT_TEXT: { + static GtkTargetEntry *text_targets = nullptr; + static int n_text_targets; + + if (text_targets == nullptr) { + auto list = gtk_target_list_new (nullptr, 0); + gtk_target_list_add_text_targets (list, VTE_TARGET_TEXT); + + text_targets = gtk_target_table_new_from_list (list, &n_text_targets); + gtk_target_list_unref (list); + } + + *n_targets = n_text_targets; + return text_targets; + } + + case VTE_FORMAT_HTML: { + static GtkTargetEntry *html_targets = nullptr; + static int n_html_targets; + + if (html_targets == nullptr) { + auto list = gtk_target_list_new (nullptr, 0); + gtk_target_list_add_text_targets (list, VTE_TARGET_TEXT); + gtk_target_list_add (list, + gdk_atom_intern_static_string("text/html"), + 0, + VTE_TARGET_HTML); + + html_targets = gtk_target_table_new_from_list (list, &n_html_targets); + gtk_target_list_unref (list); + } + + *n_targets = n_html_targets; + return html_targets; + } + default: + g_assert_not_reached(); + } } /* Place the selected text onto the clipboard. Do this asynchronously so that * we get notified when the selection we placed on the clipboard is replaced. */ void -VteTerminalPrivate::widget_copy(VteSelection sel) +VteTerminalPrivate::widget_copy(VteSelection sel, + VteFormat format) { - static GtkTargetEntry *targets = NULL; - static gint n_targets = 0; - GArray *attributes; - - attributes = g_array_new(FALSE, TRUE, sizeof(struct _VteCharAttributes)); + /* Only put HTML on the CLIPBOARD, not PRIMARY */ + g_assert(sel == VTE_SELECTION_CLIPBOARD || format == VTE_FORMAT_TEXT); /* Chuck old selected text and retrieve the newly-selected text. */ - g_free(m_selection_text[sel]); - gsize len; - m_selection_text[sel] = get_selected_text(attributes, &len); -#ifdef HTML_SELECTION - g_free(m_selection_html[sel]); - m_selection_html[sel] = attributes_to_html(m_selection_text[sel], len, - attributes); -#endif + GArray *attributes = g_array_new(FALSE, TRUE, sizeof(struct _VteCharAttributes)); + auto selection = get_selected_text(attributes); + + if (m_selection[sel]) { + g_string_free(m_selection[sel], TRUE); + m_selection[sel] = nullptr; + } + + if (selection == nullptr) { + g_array_free(attributes, TRUE); + m_has_selection = FALSE; + m_selection_owned[sel] = false; + return; + } + + if (format == VTE_FORMAT_HTML) { + m_selection[sel] = attributes_to_html(selection, attributes); + g_string_free(selection, TRUE); + } else { + m_selection[sel] = selection; + } g_array_free (attributes, TRUE); @@ -6352,38 +6390,24 @@ VteTerminalPrivate::widget_copy(VteSelection sel) m_has_selection = TRUE; /* Place the text on the clipboard. */ - if (m_selection_text[sel] != NULL) { - _vte_debug_print(VTE_DEBUG_SELECTION, - "Assuming ownership of selection.\n"); - if (!targets) { - GtkTargetList *list; - - list = gtk_target_list_new (NULL, 0); - gtk_target_list_add_text_targets (list, VTE_TARGET_TEXT); - -#ifdef HTML_SELECTION - gtk_target_list_add (list, - gdk_atom_intern("text/html", FALSE), - 0, - VTE_TARGET_HTML); -#endif + _vte_debug_print(VTE_DEBUG_SELECTION, + "Assuming ownership of selection.\n"); - targets = gtk_target_table_new_from_list (list, &n_targets); - gtk_target_list_unref (list); - } + int n_targets; + auto targets = targets_for_format(format, &n_targets); - m_changing_selection = true; - gtk_clipboard_set_with_data(m_clipboard[sel], - targets, - n_targets, - clipboard_copy_cb, - clipboard_clear_cb, - this); - m_changing_selection = false; + m_changing_selection = true; + gtk_clipboard_set_with_data(m_clipboard[sel], + targets, + n_targets, + clipboard_copy_cb, + clipboard_clear_cb, + this); + m_changing_selection = false; - gtk_clipboard_set_can_store(m_clipboard[sel], NULL, 0); - m_selection_owned[sel] = true; - } + gtk_clipboard_set_can_store(m_clipboard[sel], nullptr, 0); + m_selection_owned[sel] = true; + m_selection_format[sel] = format; } /* Paste from the given clipboard. */ @@ -6505,7 +6529,7 @@ VteTerminalPrivate::maybe_end_selection() if (m_has_selection && !m_selecting_restart && m_selecting_had_delta) { - widget_copy(VTE_SELECTION_PRIMARY); + widget_copy(VTE_SELECTION_PRIMARY, VTE_FORMAT_TEXT); emit_selection_changed(); } m_selecting = false; @@ -6977,7 +7001,7 @@ VteTerminalPrivate::select_all() _vte_debug_print(VTE_DEBUG_SELECTION, "Selecting *all* text.\n"); - widget_copy(VTE_SELECTION_PRIMARY); + widget_copy(VTE_SELECTION_PRIMARY, VTE_FORMAT_TEXT); emit_selection_changed(); invalidate_all(); @@ -8434,16 +8458,16 @@ VteTerminalPrivate::~VteTerminalPrivate() * throw the text onto the clipboard without an owner so that it * doesn't just disappear. */ for (sel = VTE_SELECTION_PRIMARY; sel < LAST_VTE_SELECTION; sel++) { - if (m_selection_text[sel] != NULL) { + if (m_selection[sel] != nullptr) { if (m_selection_owned[sel]) { + // FIXMEchpe we should check m_selection_format[sel] + // and also put text/html on if it's VTE_FORMAT_HTML gtk_clipboard_set_text(m_clipboard[sel], - m_selection_text[sel], - -1); + m_selection[sel]->str, + m_selection[sel]->len); } - g_free(m_selection_text[sel]); -#ifdef HTML_SELECTION - g_free(m_selection_html[sel]); -#endif + g_string_free(m_selection[sel], TRUE); + m_selection[sel] = nullptr; } } @@ -10327,13 +10351,9 @@ VteTerminalPrivate::reset(bool clear_tabstops, m_selecting_restart = FALSE; m_selecting_had_delta = FALSE; for (int sel = VTE_SELECTION_PRIMARY; sel < LAST_VTE_SELECTION; sel++) { - if (m_selection_text[sel] != NULL) { - g_free(m_selection_text[sel]); - m_selection_text[sel] = NULL; -#ifdef HTML_SELECTION - g_free(m_selection_html[sel]); - m_selection_html[sel] = NULL; -#endif + if (m_selection[sel] != nullptr) { + g_string_free(m_selection[sel], TRUE); + m_selection[sel] = nullptr; } m_selection_owned[sel] = false; } @@ -10459,7 +10479,7 @@ VteTerminalPrivate::select_text(vte::grid::column_t start_col, m_selection_start.row = start_row; m_selection_end.col = end_col; m_selection_end.row = end_row; - widget_copy(VTE_SELECTION_PRIMARY); + widget_copy(VTE_SELECTION_PRIMARY, VTE_FORMAT_TEXT); emit_selection_changed(); invalidate_region(MIN (start_col, end_col), MAX (start_col, end_col), @@ -11029,22 +11049,18 @@ VteTerminalPrivate::search_rows(pcre2_match_context_8 *match_context, vte::grid::row_t end_row, bool backward) { - char *row_text; - gsize row_text_length; int start, end; long start_col, end_col; - gchar *word; VteCharAttributes *ca; GArray *attrs; gdouble value, page_size; - row_text = get_text(start_row, 0, - end_row, -1, - false /* block */, - true /* wrap */, - false /* include trailing whitespace */, /* FIXMEchpe maybe do include it since the match may depend on it? */ - nullptr, - &row_text_length); + auto row_text = get_text(start_row, 0, + end_row, -1, + false /* block */, + true /* wrap */, + false /* include trailing whitespace */, /* FIXMEchpe maybe do include it since the match may depend on it? */ + nullptr); int (* match_fn) (const pcre2_code_8 *, PCRE2_SPTR8, PCRE2_SIZE, PCRE2_SIZE, uint32_t, @@ -11058,7 +11074,7 @@ VteTerminalPrivate::search_rows(pcre2_match_context_8 *match_context, match_fn = pcre2_match_8; r = match_fn(_vte_regex_get_pcre(m_search_regex.regex), - (PCRE2_SPTR8)row_text, row_text_length , /* subject, length */ + (PCRE2_SPTR8)row_text->str, row_text->len , /* subject, length */ 0, /* start offset */ m_search_regex.match_flags | PCRE2_NO_UTF_CHECK | PCRE2_NOTEMPTY | PCRE2_PARTIAL_SOFT /* FIXME: HARD? */, @@ -11079,10 +11095,9 @@ VteTerminalPrivate::search_rows(pcre2_match_context_8 *match_context, start = so; end = eo; - word = g_strndup(row_text, end - start); /* Fetch text again, with attributes */ - g_free (row_text); + g_string_free(row_text, TRUE); if (!m_search_attrs) m_search_attrs = g_array_new (FALSE, TRUE, sizeof (VteCharAttributes)); attrs = m_search_attrs; @@ -11091,8 +11106,7 @@ VteTerminalPrivate::search_rows(pcre2_match_context_8 *match_context, false /* block */, true /* wrap */, false /* include trailing whitespace */, /* FIXMEchpe maybe true? */ - attrs, - nullptr); + attrs); ca = &g_array_index (attrs, VteCharAttributes, start); start_row = ca->row; @@ -11101,8 +11115,7 @@ VteTerminalPrivate::search_rows(pcre2_match_context_8 *match_context, end_row = ca->row; end_col = ca->column; - g_free (word); - g_free (row_text); + g_string_free (row_text, TRUE); select_text(start_col, start_row, end_col, end_row); /* Quite possibly the math here should not access adjustment directly... */ diff --git a/src/vte/vtedeprecated.h b/src/vte/vtedeprecated.h index e6aba8f4..d0a0c29b 100644 --- a/src/vte/vtedeprecated.h +++ b/src/vte/vtedeprecated.h @@ -89,6 +89,10 @@ _VTE_DEPRECATED _VTE_PUBLIC void vte_pty_close (VtePty *pty) _VTE_GNUC_NONNULL(1); +_VTE_DEPRECATED +_VTE_PUBLIC +void vte_terminal_copy_clipboard(VteTerminal *terminal) _VTE_GNUC_NONNULL(1); + G_END_DECLS #undef _VTE_DEPRECATED diff --git a/src/vte/vteenums.h b/src/vte/vteenums.h index 10069633..0e71715c 100644 --- a/src/vte/vteenums.h +++ b/src/vte/vteenums.h @@ -137,6 +137,21 @@ typedef enum { VTE_REGEX_ERROR_NOT_SUPPORTED = G_MAXINT } VteRegexError; +/** + * VteFormat: + * @VTE_FORMAT_TEXT: Export as plain text + * @VTE_FORMAT_HTML: Export as HTML formatted text + * + * An enumeratio type that can be used to specify the format the selection + * should be copied to the clipboard in. + * + * Since: 0.50 + */ +typedef enum { + VTE_FORMAT_TEXT = 1, + VTE_FORMAT_HTML = 2 +} VteFormat; + G_END_DECLS #endif /* __VTE_VTE_ENUMS_H__ */ diff --git a/src/vte/vteterminal.h b/src/vte/vteterminal.h index 40cdc4f5..cfd5a911 100644 --- a/src/vte/vteterminal.h +++ b/src/vte/vteterminal.h @@ -178,7 +178,8 @@ void vte_terminal_feed_child_binary(VteTerminal *terminal, /* Copy currently-selected text to the clipboard, or from the clipboard to * the terminal. */ _VTE_PUBLIC -void vte_terminal_copy_clipboard(VteTerminal *terminal) _VTE_GNUC_NONNULL(1); +void vte_terminal_copy_clipboard_format(VteTerminal *terminal, + VteFormat format) _VTE_GNUC_NONNULL(1); _VTE_PUBLIC void vte_terminal_paste_clipboard(VteTerminal *terminal) _VTE_GNUC_NONNULL(1); _VTE_PUBLIC diff --git a/src/vteaccess.cc b/src/vteaccess.cc index 31eaec12..3bc68f01 100644 --- a/src/vteaccess.cc +++ b/src/vteaccess.cc @@ -1422,7 +1422,7 @@ vte_terminal_accessible_get_selection(AtkText *text, gint selection_number, auto impl = IMPL_FROM_WIDGET(widget); - if (!impl->m_has_selection) + if (!impl->m_has_selection || impl->m_selection[VTE_SELECTION_PRIMARY] == nullptr) return NULL; auto start_sel = impl->m_selection_start; @@ -1431,7 +1431,7 @@ vte_terminal_accessible_get_selection(AtkText *text, gint selection_number, *start_offset = offset_from_xy (priv, start_sel.col, start_sel.row); *end_offset = offset_from_xy (priv, end_sel.col, end_sel.row); - return g_strdup(impl->m_selection_text[VTE_SELECTION_PRIMARY]); + return g_strdup(impl->m_selection[VTE_SELECTION_PRIMARY]->str); } static gboolean diff --git a/src/vtegtk.cc b/src/vtegtk.cc index 0f077e2e..68a1dce7 100644 --- a/src/vtegtk.cc +++ b/src/vtegtk.cc @@ -140,7 +140,7 @@ vte_terminal_set_vscroll_policy(VteTerminal *terminal, static void vte_terminal_real_copy_clipboard(VteTerminal *terminal) { - IMPL(terminal)->widget_copy(VTE_SELECTION_CLIPBOARD); + IMPL(terminal)->widget_copy(VTE_SELECTION_CLIPBOARD, VTE_FORMAT_TEXT); } static void @@ -1678,6 +1678,9 @@ vte_terminal_new(void) * * Places the selected text in the terminal in the #GDK_SELECTION_CLIPBOARD * selection. + * + * Deprecated: 0.50: Use vte_terminal_copy_clipboard_format() with %VTE_FORMAT_TEXT + * instead. */ void vte_terminal_copy_clipboard(VteTerminal *terminal) @@ -1687,6 +1690,34 @@ vte_terminal_copy_clipboard(VteTerminal *terminal) IMPL(terminal)->emit_copy_clipboard(); } + +/** + * vte_terminal_copy_clipboard_format: + * @terminal: a #VteTerminal + * @format: a #VteFormat + * + * Places the selected text in the terminal in the #GDK_SELECTION_CLIPBOARD + * selection in the form specified by @format. + * + * For all formats, the selection data (see #GtkSelectionData) will include the + * text targets (see gtk_target_list_add_text_targets() and + * gtk_selection_data_targets_includes_text()). For %VTE_FORMAT_HTML, + * the selection will also include the "text/html" target, which when requested, + * returns the HTML data in UTF-16 with a U+FEFF BYTE ORDER MARK character at + * the start. + * + * Since: 0.50 + */ +void +vte_terminal_copy_clipboard_format(VteTerminal *terminal, + VteFormat format) +{ + g_return_if_fail(VTE_IS_TERMINAL(terminal)); + g_return_if_fail(format == VTE_FORMAT_TEXT || format == VTE_FORMAT_HTML); + + IMPL(terminal)->widget_copy(VTE_SELECTION_CLIPBOARD, format); +} + /** * vte_terminal_copy_primary: * @terminal: a #VteTerminal @@ -1699,7 +1730,7 @@ vte_terminal_copy_primary(VteTerminal *terminal) { g_return_if_fail(VTE_IS_TERMINAL(terminal)); _vte_debug_print(VTE_DEBUG_SELECTION, "Copying to PRIMARY.\n"); - IMPL(terminal)->widget_copy(VTE_SELECTION_PRIMARY); + IMPL(terminal)->widget_copy(VTE_SELECTION_PRIMARY, VTE_FORMAT_TEXT); } /** @@ -2672,10 +2703,12 @@ vte_terminal_get_text(VteTerminal *terminal, { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); warn_if_callback(is_selected); - return IMPL(terminal)->get_text_displayed(true /* wrap */, - false /* include trailing whitespace */, - attributes, - nullptr); + auto text = IMPL(terminal)->get_text_displayed(true /* wrap */, + false /* include trailing whitespace */, + attributes); + if (text == nullptr) + return nullptr; + return (char*)g_string_free(text, FALSE); } /** @@ -2703,10 +2736,12 @@ vte_terminal_get_text_include_trailing_spaces(VteTerminal *terminal, { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); warn_if_callback(is_selected); - return IMPL(terminal)->get_text_displayed(true /* wrap */, - true /* include trailing whitespace */, - attributes, - nullptr); + auto text = IMPL(terminal)->get_text_displayed(true /* wrap */, + true /* include trailing whitespace */, + attributes); + if (text == nullptr) + return nullptr; + return (char*)g_string_free(text, FALSE); } /** @@ -2742,13 +2777,15 @@ vte_terminal_get_text_range(VteTerminal *terminal, { g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL); warn_if_callback(is_selected); - return IMPL(terminal)->get_text(start_row, start_col, - end_row, end_col, - false /* block */, - true /* wrap */, - true /* include trailing whitespace */, - attributes, - nullptr); + auto text = IMPL(terminal)->get_text(start_row, start_col, + end_row, end_col, + false /* block */, + true /* wrap */, + true /* include trailing whitespace */, + attributes); + if (text == nullptr) + return nullptr; + return (char*)g_string_free(text, FALSE); } /** diff --git a/src/vteinternal.hh b/src/vteinternal.hh index 7eea9419..677e61a7 100644 --- a/src/vteinternal.hh +++ b/src/vteinternal.hh @@ -357,11 +357,9 @@ public: /* Clipboard data information. */ // FIXMEchpe check if this can make m_has_selection obsolete! bool m_selection_owned[LAST_VTE_SELECTION]; + VteFormat m_selection_format[LAST_VTE_SELECTION]; bool m_changing_selection; - char *m_selection_text[LAST_VTE_SELECTION]; -#ifdef HTML_SELECTION - char *m_selection_html[LAST_VTE_SELECTION]; -#endif + GString *m_selection[LAST_VTE_SELECTION]; GtkClipboard *m_clipboard[LAST_VTE_SELECTION]; ClipboardTextRequestGtk<VteTerminalPrivate> m_paste_request; @@ -647,7 +645,8 @@ public: void widget_paste(GdkAtom board); - void widget_copy(VteSelection sel); + void widget_copy(VteSelection sel, + VteFormat format); void widget_paste_received(char const* text); void widget_clipboard_cleared(GtkClipboard *clipboard); void widget_clipboard_requested(GtkClipboard *target_clipboard, @@ -826,33 +825,17 @@ public: bool block, bool wrap, bool include_trailing_spaces, - GArray *attributes); - - char* get_text(vte::grid::row_t start_row, - vte::grid::column_t start_col, - vte::grid::row_t end_row, - vte::grid::column_t end_col, - bool block, - bool wrap, - bool include_trailing_spaces, - GArray *attributes, - gsize *ret_len); + GArray* attributes = nullptr); GString* get_text_displayed(bool wrap, bool include_trailing_spaces, - GArray *attributes); - - char* get_text_displayed(bool wrap, - bool include_trailing_spaces, - GArray *attributes, - gsize *ret_len); + GArray* attributes = nullptr); GString* get_text_displayed_a11y(bool wrap, bool include_trailing_spaces, - GArray *attributes); + GArray* attributes = nullptr); - char *get_selected_text(GArray *attributes = nullptr, - gsize *len_ptr = nullptr); + GString* get_selected_text(GArray* attributes = nullptr); inline void rgb_from_index(guint index, vte::color::rgb& color) const; @@ -874,9 +857,8 @@ public: char const* text) const; VteCellAttr const* char_to_cell_attr(VteCharAttributes const* attr) const; - char *attributes_to_html(char const* text, - gsize len, - GArray *attrs); + GString* attributes_to_html(GString* text_string, + GArray* attrs); void start_selection(long x, long y, |