summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Persch <chpe@src.gnome.org>2017-05-07 13:57:41 +0200
committerChristian Persch <chpe@src.gnome.org>2017-05-07 13:57:41 +0200
commit91e9c83878ee389ad63f45c7ec654011b75039e5 (patch)
tree41ffca3c1098308c96d0bd35ad0d4ce787e4e700
parent64be114a87ad20e874860a7a819c16fa394c69f8 (diff)
downloadvte-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.ui1
-rw-r--r--bindings/vala/app.vala12
-rw-r--r--doc/reference/vte-sections.txt6
-rw-r--r--src/vte.cc325
-rw-r--r--src/vte/vtedeprecated.h4
-rw-r--r--src/vte/vteenums.h15
-rw-r--r--src/vte/vteterminal.h3
-rw-r--r--src/vteaccess.cc4
-rw-r--r--src/vtegtk.cc71
-rw-r--r--src/vteinternal.hh38
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
diff --git a/src/vte.cc b/src/vte.cc
index 3cb83433..df1220e1 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -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,