Consolidate TextView/TextBuffer attribute serialization

Use dictionaries of string pairs instead of abusing GVariant; we can
convert the dictionary into a GVariant when we send the data over the
wire.
This commit is contained in:
Emmanuele Bassi 2024-03-04 19:13:29 +00:00
parent 2774e80fc4
commit 644e6f8ebe
8 changed files with 259 additions and 284 deletions

View File

@ -1682,63 +1682,79 @@ text_view_handle_method (GDBusConnection *connection,
}
else if (g_strcmp0 (method_name, "GetAttributes") == 0)
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
GHashTable *attrs;
GHashTableIter iter;
int offset;
int start, end;
gpointer key, value;
g_variant_get (parameters, "(i)", &offset);
gtk_text_buffer_get_run_attributes (buffer, &builder, offset, &start, &end);
attrs = gtk_text_view_get_attributes_run (GTK_TEXT_VIEW (widget), offset, FALSE, &start, &end);
g_hash_table_iter_init (&iter, attrs);
while (g_hash_table_iter_next (&iter, &key, &value))
g_variant_builder_add (&builder, "{ss}", key, value != NULL ? value : "");
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
g_hash_table_unref (attrs);
}
else if (g_strcmp0 (method_name, "GetAttributeValue") == 0)
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
const char *name;
int start, end;
GVariant *attrs;
const char *val;
GHashTable *attrs;
g_variant_get (parameters, "(i&s)", &offset, &name);
gtk_text_buffer_get_run_attributes (buffer, &builder, offset, &start, &end);
attrs = g_variant_builder_end (&builder);
if (!g_variant_lookup (attrs, name, "&s", &val))
attrs = gtk_text_view_get_attributes_run (GTK_TEXT_VIEW (widget), offset, FALSE, &start, &end);
val = g_hash_table_lookup (attrs, name);
if (val == NULL)
val = "";
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", val));
g_variant_unref (attrs);
g_hash_table_unref (attrs);
}
else if (g_strcmp0 (method_name, "GetAttributeRun") == 0)
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int offset;
gboolean include_defaults;
int start, end;
GHashTable *attrs;
GHashTableIter iter;
gpointer key, value;
g_variant_get (parameters, "(ib)", &offset, &include_defaults);
if (include_defaults)
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (widget), &builder);
gtk_text_buffer_get_run_attributes (buffer, &builder, offset, &start, &end);
attrs = gtk_text_view_get_attributes_run (GTK_TEXT_VIEW (widget), offset, include_defaults, &start, &end);
g_hash_table_iter_init (&iter, attrs);
while (g_hash_table_iter_next (&iter, &key, &value))
g_variant_builder_add (&builder, "{ss}", key, value != NULL ? value : "");
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
g_hash_table_unref (attrs);
}
else if (g_strcmp0 (method_name, "GetDefaultAttributes") == 0 ||
g_strcmp0 (method_name, "GetDefaultAttributeSet") == 0)
{
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
GHashTable *attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
GHashTableIter iter;
gpointer key, value;
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (widget), &builder);
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (widget), attrs);
g_hash_table_iter_init (&iter, attrs);
while (g_hash_table_iter_next (&iter, &key, &value))
g_variant_builder_add (&builder, "{ss}", key, value != NULL ? value : "");
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder));
g_hash_table_unref (attrs);
}
else if (g_strcmp0 (method_name, "GetNSelections") == 0)
{

View File

@ -23,101 +23,6 @@
#include "gtktextviewprivate.h"
#include "gtkpangoprivate.h"
void
gtk_text_view_add_default_attributes (GtkTextView *view,
GVariantBuilder *builder)
{
GtkTextAttributes *text_attrs;
PangoFontDescription *font;
char *value;
text_attrs = gtk_text_view_get_default_attributes (view);
font = text_attrs->font;
if (font)
{
char **names, **values;
gtk_pango_get_font_attributes (font, &names, &values);
for (unsigned i = 0; names[i] != NULL; i++)
g_variant_builder_add (builder, "{ss}", names[i], values[i]);
g_strfreev (names);
g_strfreev (values);
}
g_variant_builder_add (builder, "{ss}", "justification",
gtk_justification_to_string (text_attrs->justification));
g_variant_builder_add (builder, "{ss}", "direction",
gtk_text_direction_to_string (text_attrs->direction));
g_variant_builder_add (builder, "{ss}", "wrap-mode",
gtk_wrap_mode_to_string (text_attrs->wrap_mode));
g_variant_builder_add (builder, "{ss}", "editable",
text_attrs->editable ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "invisible",
text_attrs->invisible ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "bg-full-height",
text_attrs->bg_full_height ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "strikethrough",
text_attrs->appearance.strikethrough ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "underline",
pango_underline_to_string (text_attrs->appearance.underline));
value = g_strdup_printf ("%u,%u,%u",
(guint)(text_attrs->appearance.bg_rgba->red * 65535),
(guint)(text_attrs->appearance.bg_rgba->green * 65535),
(guint)(text_attrs->appearance.bg_rgba->blue * 65535));
g_variant_builder_add (builder, "{ss}", "bg-color", value);
g_free (value);
value = g_strdup_printf ("%u,%u,%u",
(guint)(text_attrs->appearance.fg_rgba->red * 65535),
(guint)(text_attrs->appearance.fg_rgba->green * 65535),
(guint)(text_attrs->appearance.fg_rgba->blue * 65535));
g_variant_builder_add (builder, "{ss}", "bg-color", value);
g_free (value);
value = g_strdup_printf ("%g", text_attrs->font_scale);
g_variant_builder_add (builder, "{ss}", "scale", value);
g_free (value);
value = g_strdup ((gchar *)(text_attrs->language));
g_variant_builder_add (builder, "{ss}", "language", value);
g_free (value);
value = g_strdup_printf ("%i", text_attrs->appearance.rise);
g_variant_builder_add (builder, "{ss}", "rise", value);
g_free (value);
value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
g_variant_builder_add (builder, "{ss}", "pixels-inside-wrap", value);
g_free (value);
value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
g_variant_builder_add (builder, "{ss}", "pixels-below-lines", value);
g_free (value);
value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
g_variant_builder_add (builder, "{ss}", "pixels-above-lines", value);
g_free (value);
value = g_strdup_printf ("%i", text_attrs->indent);
g_variant_builder_add (builder, "{ss}", "indent", value);
g_free (value);
value = g_strdup_printf ("%i", text_attrs->left_margin);
g_variant_builder_add (builder, "{ss}", "left-margin", value);
g_free (value);
value = g_strdup_printf ("%i", text_attrs->right_margin);
g_variant_builder_add (builder, "{ss}", "right-margin", value);
g_free (value);
gtk_text_attributes_unref (text_attrs);
}
char *
gtk_text_view_get_text_before (GtkTextView *view,
int offset,

View File

@ -23,9 +23,6 @@
G_BEGIN_DECLS
void gtk_text_view_add_default_attributes (GtkTextView *view,
GVariantBuilder *builder);
char *gtk_text_view_get_text_before (GtkTextView *view,
int offset,
AtspiTextBoundaryType boundary_type,

View File

@ -5189,27 +5189,27 @@ gtk_wrap_mode_to_string (GtkWrapMode wrap_mode)
}
/*< private >
* gtk_text_buffer_get_run_attributes:
* gtk_text_buffer_add_run_attributes:
* @buffer: the buffer to serialize
* @builder: the target `GVariant` builder
* @offset: the offset into the text buffer
* @attributes: a hash table of serialized text attributes
* @start_offset: (out): the start offset for the attributes run
* @end_offset: (out): the end offset for the attributes run
*
* Serializes the attributes inside a text buffer at the given offset.
*
* All attributes are serializes as a dictionary of string keys
* and string values, `a{ss}`.
* All attributes are serialized as key/value string pairs inside the
* provided @attributes dictionary.
*
* The serialization format is private to GTK and should not be
* considered stable.
*/
void
gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
GVariantBuilder *builder,
int offset,
int *start_offset,
int *end_offset)
gtk_text_buffer_add_run_attributes (GtkTextBuffer *buffer,
int offset,
GHashTable *attributes,
int *start_offset,
int *end_offset)
{
GtkTextIter iter;
GSList *tags, *temp_tags;
@ -5240,7 +5240,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"style", &style,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "style", pango_style_to_string (style));
g_hash_table_insert (attributes,
g_strdup ("style"),
g_strdup (pango_style_to_string (style)));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5256,7 +5258,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"variant", &variant,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "variant", pango_variant_to_string (variant));
g_hash_table_insert (attributes,
g_strdup ("variant"),
g_strdup (pango_variant_to_string (variant)));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5272,7 +5276,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"stretch", &stretch,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "stretch", pango_stretch_to_string (stretch));
g_hash_table_insert (attributes,
g_strdup ("stretch"),
g_strdup (pango_stretch_to_string (stretch)));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5288,7 +5294,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"justification", &justification,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "justification", gtk_justification_to_string (justification));
g_hash_table_insert (attributes,
g_strdup ("justification"),
g_strdup (gtk_justification_to_string (justification)));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5303,7 +5311,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
if (direction != GTK_TEXT_DIR_NONE)
{
val_set = TRUE;
g_variant_builder_add (builder, "{ss}", "direction", gtk_text_direction_to_string (direction));
g_hash_table_insert (attributes,
g_strdup ("direction"),
g_strdup (gtk_text_direction_to_string (direction)));
}
temp_tags = temp_tags->next;
}
@ -5320,7 +5330,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"wrap-mode", &wrap_mode,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "wrap-mode", gtk_wrap_mode_to_string (wrap_mode));
g_hash_table_insert (attributes,
g_strdup ("wrap-mode"),
g_strdup (gtk_wrap_mode_to_string (wrap_mode)));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5342,8 +5354,8 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
(guint) rgba->green * 65535,
(guint) rgba->blue * 65535);
gdk_rgba_free (rgba);
g_variant_builder_add (builder, "{ss}", "fg-color", value);
g_free (value);
g_hash_table_insert (attributes, g_strdup ("fg-color"), value);
}
temp_tags = temp_tags->next;
}
@ -5366,8 +5378,8 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
(guint) rgba->green * 65535,
(guint) rgba->blue * 65535);
gdk_rgba_free (rgba);
g_variant_builder_add (builder, "{ss}", "bg-color", value);
g_free (value);
g_hash_table_insert (attributes, g_strdup ("bg-color"), value);
}
temp_tags = temp_tags->next;
}
@ -5384,8 +5396,8 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
{
char *value;
g_object_get (tag, "family", &value, NULL);
g_variant_builder_add (builder, "{ss}", "family-name", value);
g_free (value);
g_hash_table_insert (attributes, g_strdup ("family-name"), value);
}
temp_tags = temp_tags->next;
}
@ -5402,8 +5414,7 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
{
char *value;
g_object_get (tag, "language", &value, NULL);
g_variant_builder_add (builder, "{ss}", "language", value);
g_free (value);
g_hash_table_insert (attributes, g_strdup ("language"), value);
}
temp_tags = temp_tags->next;
}
@ -5422,10 +5433,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
if (val_set)
{
char *value;
value = g_strdup_printf ("%d", weight);
g_variant_builder_add (builder, "{ss}", "weight", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("weight"),
g_strdup_printf ("%d", weight));
}
temp_tags = temp_tags->next;
}
@ -5452,9 +5462,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
}
if (val_set)
{
char *value = g_strdup_printf ("%g", scale);
g_variant_builder_add (builder, "{ss}", "scale", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("scale"),
g_strdup_printf ("%g", scale));
}
val_set = FALSE;
@ -5470,9 +5480,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", size);
g_variant_builder_add (builder, "{ss}", "size", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("size"),
g_strdup_printf ("%i", size));
}
temp_tags = temp_tags->next;
}
@ -5489,7 +5499,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"strikethrough", &strikethrough,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "strikethrough", strikethrough ? "true" : "false");
g_hash_table_insert (attributes,
g_strdup ("strikethrough"),
strikethrough ? g_strdup ("true") : g_strdup ("false"));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5505,8 +5517,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"underline", &underline,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "underline",
pango_underline_to_string (underline));
g_hash_table_insert (attributes,
g_strdup ("underline"),
g_strdup (pango_underline_to_string (underline)));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5523,9 +5536,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", rise);
g_variant_builder_add (builder, "{ss}", "rise", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("rise"),
g_strdup_printf ("%i", rise));
}
temp_tags = temp_tags->next;
}
@ -5542,7 +5555,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"background-full-height", &bg_full_height,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "bg-full-height", bg_full_height ? "true" : "false");
g_hash_table_insert (attributes,
g_strdup ("bg-full-height"),
bg_full_height ? g_strdup ("true") : g_strdup ("false"));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5559,9 +5574,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", pixels);
g_variant_builder_add (builder, "{ss}", "pixels-inside-wrap", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("pixels-inside-wrap"),
g_strdup_printf ("%i", pixels));
}
temp_tags = temp_tags->next;
}
@ -5579,9 +5594,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", pixels);
g_variant_builder_add (builder, "{ss}", "pixels-below-lines", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("pixels-below-lines"),
g_strdup_printf ("%i", pixels));
}
temp_tags = temp_tags->next;
}
@ -5599,9 +5614,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", pixels);
g_variant_builder_add (builder, "{ss}", "pixels-above-lines", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("pixels-above-lines"),
g_strdup_printf ("%i", pixels));
}
temp_tags = temp_tags->next;
}
@ -5618,7 +5633,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"editable", &editable,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "editable", editable ? "true" : "false");
g_hash_table_insert (attributes,
g_strdup ("editable"),
editable ? g_strdup ("true") : g_strdup ("false"));
temp_tags = temp_tags->next;
}
val_set = FALSE;
@ -5634,12 +5651,14 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
"invisible", &invisible,
NULL);
if (val_set)
g_variant_builder_add (builder, "{ss}", "invisible", invisible ? "true" : "false");
g_hash_table_insert (attributes,
g_strdup ("invisible"),
invisible ? g_strdup ("true") : g_strdup ("false"));
temp_tags = temp_tags->next;
}
val_set = FALSE;
temp_tags = tags;
temp_tags = tags;
while (temp_tags && !val_set)
{
GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
@ -5651,9 +5670,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", indent);
g_variant_builder_add (builder, "{ss}", "indent", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("indent"),
g_strdup_printf ("%i", indent));
}
temp_tags = temp_tags->next;
}
@ -5671,9 +5690,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", margin);
g_variant_builder_add (builder, "{ss}", "right-margin", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("right-margin"),
g_strdup_printf ("%i", margin));
}
temp_tags = temp_tags->next;
}
@ -5691,9 +5710,9 @@ gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
NULL);
if (val_set)
{
char *value = g_strdup_printf ("%i", margin);
g_variant_builder_add (builder, "{ss}", "left-margin", value);
g_free (value);
g_hash_table_insert (attributes,
g_strdup ("left-margin"),
g_strdup_printf ("%i", margin));
}
temp_tags = temp_tags->next;
}

View File

@ -38,11 +38,10 @@ const char *gtk_justification_to_string (GtkJustification just);
const char *gtk_text_direction_to_string (GtkTextDirection direction);
const char *gtk_wrap_mode_to_string (GtkWrapMode wrap_mode);
void gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
GVariantBuilder *builder,
void gtk_text_buffer_add_run_attributes (GtkTextBuffer *buffer,
int offset,
GHashTable *attributes,
int *start_offset,
int *end_offset);
G_END_DECLS

View File

@ -10432,49 +10432,55 @@ gtk_text_view_accessible_text_get_attributes (GtkAccessibleText *self,
char ***attribute_values)
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
GHashTable *attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
GHashTableIter iter;
gpointer key, value;
guint n_attrs, i;
int start, end;
gtk_text_buffer_get_run_attributes (buffer, &builder, offset, &start, &end);
gtk_text_buffer_add_run_attributes (buffer, offset, attrs, &start, &end);
GVariant *v = g_variant_builder_end (&builder);
unsigned n = g_variant_n_children (v);
if (n == 0)
n_attrs = g_hash_table_size (attrs);
if (n_attrs == 0)
{
g_variant_unref (v);
g_hash_table_unref (attrs);
*n_ranges = 0;
*ranges = NULL;
*attribute_names = NULL;
*attribute_values = NULL;
return FALSE;
}
*n_ranges = n;
*ranges = g_new (GtkAccessibleTextRange, n);
*attribute_names = g_new (char *, n + 1);
*attribute_values = g_new (char *, n + 1);
*n_ranges = n_attrs;
*ranges = g_new (GtkAccessibleTextRange, n_attrs);
*attribute_names = g_new (char *, n_attrs + 1);
*attribute_values = g_new (char *, n_attrs + 1);
for (int i = 0; i < n; i++)
i = 0;
g_hash_table_iter_init (&iter, attrs);
while (g_hash_table_iter_next (&iter, &key, &value))
{
char *name, *value;
((*ranges)[i]).start = start;
((*ranges)[i]).length = end - start;
g_variant_get_child (v, i, "{ss}", &name, &value);
(*attribute_names)[i] = g_steal_pointer (&name);
(*attribute_values)[i] = g_steal_pointer (&value);
(*attribute_names)[i] = g_strdup (key);
(*attribute_values)[i] = g_strdup (value);
i += 1;
}
(*attribute_names)[n] = NULL;
(*attribute_values)[n] = NULL;
(*attribute_names)[n_attrs] = NULL;
(*attribute_values)[n_attrs] = NULL;
return TRUE;
}
static void
gtk_text_view_add_default_attributes (GtkTextView *view,
GVariantBuilder *builder)
void
gtk_text_view_add_default_attributes (GtkTextView *view,
GHashTable *attributes)
{
GtkTextAttributes *text_attrs;
PangoFontDescription *font;
char *value;
text_attrs = gtk_text_view_get_default_attributes (view);
@ -10487,112 +10493,144 @@ gtk_text_view_add_default_attributes (GtkTextView *view,
gtk_pango_get_font_attributes (font, &names, &values);
for (unsigned i = 0; names[i] != NULL; i++)
g_variant_builder_add (builder, "{ss}", names[i], values[i]);
g_hash_table_insert (attributes,
g_steal_pointer (&names[i]),
g_steal_pointer (&values[i]));
g_strfreev (names);
g_strfreev (values);
g_free (names);
g_free (values);
}
g_variant_builder_add (builder, "{ss}", "justification",
gtk_justification_to_string (text_attrs->justification));
g_variant_builder_add (builder, "{ss}", "direction",
gtk_text_direction_to_string (text_attrs->direction));
g_variant_builder_add (builder, "{ss}", "wrap-mode",
gtk_wrap_mode_to_string (text_attrs->wrap_mode));
g_variant_builder_add (builder, "{ss}", "editable",
text_attrs->editable ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "invisible",
text_attrs->invisible ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "bg-full-height",
text_attrs->bg_full_height ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "strikethrough",
text_attrs->appearance.strikethrough ? "true" : "false");
g_variant_builder_add (builder, "{ss}", "underline",
pango_underline_to_string (text_attrs->appearance.underline));
#define ADD_STR_ATTR(ht,name,value) \
g_hash_table_insert ((ht), g_strdup ((name)), g_strdup ((value)))
value = g_strdup_printf ("%u,%u,%u",
(guint)(text_attrs->appearance.bg_rgba->red * 65535),
(guint)(text_attrs->appearance.bg_rgba->green * 65535),
(guint)(text_attrs->appearance.bg_rgba->blue * 65535));
g_variant_builder_add (builder, "{ss}", "bg-color", value);
g_free (value);
#define ADD_BOOL_ATTR(ht,name,value) \
g_hash_table_insert ((ht), g_strdup ((name)), (value) ? g_strdup ("true") : g_strdup ("false"))
value = g_strdup_printf ("%u,%u,%u",
(guint)(text_attrs->appearance.fg_rgba->red * 65535),
(guint)(text_attrs->appearance.fg_rgba->green * 65535),
(guint)(text_attrs->appearance.fg_rgba->blue * 65535));
g_variant_builder_add (builder, "{ss}", "bg-color", value);
g_free (value);
#define ADD_COLOR_ATTR(ht,name,color) G_STMT_START { \
char *__value = g_strdup_printf ("%u,%u,%u", \
(guint) ((color)->red * 65535), \
(guint) ((color)->green * 65535), \
(guint) ((color)->blue * 65535)); \
g_hash_table_insert (ht, g_strdup (name), __value); \
} G_STMT_END
value = g_strdup_printf ("%g", text_attrs->font_scale);
g_variant_builder_add (builder, "{ss}", "scale", value);
g_free (value);
#define ADD_FLOAT_ATTR(ht,name,value) G_STMT_START { \
char *__value = g_strdup_printf ("%g", (value)); \
g_hash_table_insert (ht, g_strdup (name), __value); \
} G_STMT_END
value = g_strdup ((gchar *)(text_attrs->language));
g_variant_builder_add (builder, "{ss}", "language", value);
g_free (value);
#define ADD_INT_ATTR(ht,name,value) G_STMT_START { \
char *__value = g_strdup_printf ("%i", (value)); \
g_hash_table_insert (ht, g_strdup (name), __value); \
} G_STMT_END
value = g_strdup_printf ("%i", text_attrs->appearance.rise);
g_variant_builder_add (builder, "{ss}", "rise", value);
g_free (value);
ADD_STR_ATTR (attributes, "justification", gtk_justification_to_string (text_attrs->justification));
ADD_STR_ATTR (attributes, "direction", gtk_text_direction_to_string (text_attrs->direction));
ADD_STR_ATTR (attributes, "wrap-mode", gtk_wrap_mode_to_string (text_attrs->wrap_mode));
ADD_STR_ATTR (attributes, "underline", pango_underline_to_string (text_attrs->appearance.underline));
value = g_strdup_printf ("%i", text_attrs->pixels_inside_wrap);
g_variant_builder_add (builder, "{ss}", "pixels-inside-wrap", value);
g_free (value);
ADD_BOOL_ATTR (attributes, "editable", text_attrs->editable);
ADD_BOOL_ATTR (attributes, "invisible", text_attrs->invisible);
ADD_BOOL_ATTR (attributes, "bg-full-height", text_attrs->bg_full_height);
ADD_BOOL_ATTR (attributes, "strikethrough", text_attrs->appearance.strikethrough);
value = g_strdup_printf ("%i", text_attrs->pixels_below_lines);
g_variant_builder_add (builder, "{ss}", "pixels-below-lines", value);
g_free (value);
ADD_COLOR_ATTR (attributes, "bg-color", text_attrs->appearance.bg_rgba);
ADD_COLOR_ATTR (attributes, "fg-color", text_attrs->appearance.fg_rgba);
value = g_strdup_printf ("%i", text_attrs->pixels_above_lines);
g_variant_builder_add (builder, "{ss}", "pixels-above-lines", value);
g_free (value);
ADD_FLOAT_ATTR (attributes, "scale", text_attrs->font_scale);
value = g_strdup_printf ("%i", text_attrs->indent);
g_variant_builder_add (builder, "{ss}", "indent", value);
g_free (value);
ADD_STR_ATTR (attributes, "language", (const char *) text_attrs->language);
value = g_strdup_printf ("%i", text_attrs->left_margin);
g_variant_builder_add (builder, "{ss}", "left-margin", value);
g_free (value);
ADD_INT_ATTR (attributes, "rise", text_attrs->appearance.rise);
ADD_INT_ATTR (attributes, "pixels-inside-wrap", text_attrs->pixels_inside_wrap);
ADD_INT_ATTR (attributes, "pixels-below-lines", text_attrs->pixels_below_lines);
ADD_INT_ATTR (attributes, "pixels-above-lines", text_attrs->pixels_above_lines);
ADD_INT_ATTR (attributes, "indent", text_attrs->indent);
ADD_INT_ATTR (attributes, "left-margin", text_attrs->left_margin);
ADD_INT_ATTR (attributes, "right-margin", text_attrs->right_margin);
value = g_strdup_printf ("%i", text_attrs->right_margin);
g_variant_builder_add (builder, "{ss}", "right-margin", value);
g_free (value);
#undef ADD_STR_ATTR
#undef ADD_BOOL_ATTR
#undef ADD_COLOR_ATTR
#undef ADD_FLOAT_ATTR
#undef ADD_INT_ATTR
gtk_text_attributes_unref (text_attrs);
}
/*< private >
* gtk_text_view_get_attributes_run:
* @self: a text view
* @offset: the offset, in characters
* @include_defaults: whether the default attributes should be included
* @start: (out): the beginning of the run, in characters
* @end: (out): the end of the run, in characters
*
* Retrieves the text attributes at the given offset.
*
* The serialization format is private to GTK, but conforms to the AT-SPI
* text attributes for default attribute names.
*
* Returns: (transfer full) (element-type utf8,utf8): a dictionary of
* text attributes
*/
GHashTable *
gtk_text_view_get_attributes_run (GtkTextView *self,
int offset,
gboolean include_defaults,
int *start,
int *end)
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer (self);
GHashTable *attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
if (include_defaults)
gtk_text_view_add_default_attributes (self, attrs);
gtk_text_buffer_add_run_attributes (buffer, offset, attrs, start, end);
return attrs;
}
static void
gtk_text_view_accessible_text_get_default_attributes (GtkAccessibleText *self,
char ***attribute_names,
char ***attribute_values)
{
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
GHashTable *attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
GHashTableIter iter;
gpointer key, value;
guint n_attrs, i;
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (self), &builder);
gtk_text_view_add_default_attributes (GTK_TEXT_VIEW (self), attrs);
GVariant *v = g_variant_builder_end (&builder);
unsigned n = g_variant_n_children (v);
if (n == 0)
n_attrs = g_hash_table_size (attrs);
if (n_attrs == 0)
{
g_variant_unref (v);
g_hash_table_unref (attrs);
*attribute_names = NULL;
*attribute_values = NULL;
return;
}
*attribute_names = g_new (char *, n + 1);
*attribute_values = g_new (char *, n + 1);
*attribute_names = g_new (char *, n_attrs + 1);
*attribute_values = g_new (char *, n_attrs + 1);
for (int i = 0; i < n; i++)
i = 0;
g_hash_table_iter_init (&iter, attrs);
while (g_hash_table_iter_next (&iter, &key, &value))
{
char *name, *value;
(*attribute_names)[i] = g_strdup (key);
(*attribute_values)[i] = g_strdup (value);
g_variant_get_child (v, i, "{ss}", &name, &value);
(*attribute_names)[i] = g_steal_pointer (&name);
(*attribute_values)[i] = g_steal_pointer (&value);
i += 1;
}
(*attribute_names)[n] = NULL;
(*attribute_values)[n] = NULL;
(*attribute_names)[n_attrs] = NULL;
(*attribute_values)[n_attrs] = NULL;
g_hash_table_unref (attrs);
}
static void

View File

@ -31,6 +31,13 @@ GtkTextAttributes * gtk_text_view_get_default_attributes (GtkTextView *text_view
GtkEventController *gtk_text_view_get_key_controller (GtkTextView *text_view);
GHashTable * gtk_text_view_get_attributes_run (GtkTextView *self,
int offset,
gboolean include_defaults,
int *start,
int *end);
void gtk_text_view_add_default_attributes (GtkTextView *view,
GHashTable *attributes);
G_END_DECLS

View File

@ -1933,24 +1933,18 @@ test_serialize_wrap_mode (void)
for (i = 0; i < G_N_ELEMENTS (values); i++)
{
/* Each line has a { wrap-mode: name } run */
GVariantBuilder expected_builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
g_variant_builder_add (&expected_builder, "{ss}", "wrap-mode", values[i].name);
GVariant *expected = g_variant_builder_end (&expected_builder);
GVariantBuilder result_builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
int run_start, run_end;
gtk_text_buffer_get_run_attributes (buffer, &result_builder, 2 * i, &run_start, &run_end);
GHashTable *attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
GVariant *result = g_variant_builder_end (&result_builder);
gtk_text_buffer_add_run_attributes (buffer, 2 * i, attrs, &run_start, &run_end);
g_assert_cmpint (run_start, ==, 2 * i);
g_assert_cmpint (run_end, ==, 2 * (i + 1));
g_assert_cmpvariant (result, expected);
g_variant_unref (result);
g_variant_unref (expected);
const char *result = g_hash_table_lookup (attrs, "wrap-mode");
g_assert_cmpstr (result, ==, values[i].name);
g_hash_table_unref (attrs);
}
g_assert_finalize_object (buffer);