diff --git a/gtk/a11y/gtkatspitext.c b/gtk/a11y/gtkatspitext.c index 0bdcc7aa33..ec6e859933 100644 --- a/gtk/a11y/gtkatspitext.c +++ b/gtk/a11y/gtkatspitext.c @@ -222,12 +222,78 @@ accessible_text_handle_method (GDBusConnection *connection, } else if (g_strcmp0 (method_name, "GetAttributeRun") == 0) { - g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); + GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}")); + gboolean include_defaults = FALSE; + int offset; + gsize n_attrs = 0; + GtkAccessibleTextRange *ranges = NULL; + int start, end; + char **attr_names = NULL; + char **attr_values = NULL; + GHashTable *attrs; + + g_variant_get (parameters, "(ib)", &offset, &include_defaults); + + attrs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + if (include_defaults) + { + gtk_accessible_text_get_default_attributes (accessible_text, + &attr_names, + &attr_values); + + for (int i = 0; attr_names[i] != NULL; i++) + g_hash_table_insert (attrs, g_strdup (attr_names[i]), g_strdup (attr_values[i])); + + g_strfreev (attr_names); + g_strfreev (attr_values); + } + + gtk_accessible_text_get_attributes (accessible_text, + offset, + &n_attrs, + &ranges, + &attr_names, + &attr_values); + + start = 0; + end = G_MAXINT; + + for (int i = 0; i < n_attrs; i++) + { + g_hash_table_insert (attrs, g_strdup (attr_names[i]), g_strdup (attr_values[i])); + start = MAX (start, ranges[i].start); + end = MIN (end, start + ranges[i].length); + } + + GHashTableIter attr_iter; + gpointer key, value; + g_hash_table_iter_init (&attr_iter, attrs); + while (g_hash_table_iter_next (&attr_iter, &key, &value)) + g_variant_builder_add (&builder, "{ss}", key, value); + + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end)); + + g_clear_pointer (&attrs, g_hash_table_unref); + g_clear_pointer (&ranges, g_free); + g_strfreev (attr_names); + g_strfreev (attr_values); } else if (g_strcmp0 (method_name, "GetDefaultAttributes") == 0 || g_strcmp0 (method_name, "GetDefaultAttributeSet") == 0) { - g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, ""); + GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}")); + char **names, **values; + + gtk_accessible_text_get_default_attributes (accessible_text, &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_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss})", &builder)); } else if (g_strcmp0 (method_name, "GetNSelections") == 0) { @@ -1616,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) { diff --git a/gtk/a11y/gtkatspitextbuffer.c b/gtk/a11y/gtkatspitextbuffer.c index f733978e0b..d740c715ed 100644 --- a/gtk/a11y/gtkatspitextbuffer.c +++ b/gtk/a11y/gtkatspitextbuffer.c @@ -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, diff --git a/gtk/a11y/gtkatspitextbufferprivate.h b/gtk/a11y/gtkatspitextbufferprivate.h index 2b0017a112..1577130029 100644 --- a/gtk/a11y/gtkatspitextbufferprivate.h +++ b/gtk/a11y/gtkatspitextbufferprivate.h @@ -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, diff --git a/gtk/gtkaccessibletext-private.h b/gtk/gtkaccessibletext-private.h index 4650ab068c..0126d27a99 100644 --- a/gtk/gtkaccessibletext-private.h +++ b/gtk/gtkaccessibletext-private.h @@ -37,4 +37,10 @@ gtk_accessible_text_get_attributes (GtkAccessibleText *self, GtkAccessibleTextRange **ranges, char ***attribute_names, char ***attribute_values); + +void +gtk_accessible_text_get_default_attributes (GtkAccessibleText *self, + char ***attribute_names, + char ***attribute_values); + G_END_DECLS diff --git a/gtk/gtkaccessibletext.c b/gtk/gtkaccessibletext.c index 667765f8db..163d6f908f 100644 --- a/gtk/gtkaccessibletext.c +++ b/gtk/gtkaccessibletext.c @@ -63,6 +63,15 @@ gtk_accessible_text_default_get_attributes (GtkAccessibleText *self, return FALSE; } +static void +gtk_accessible_text_default_get_default_attributes (GtkAccessibleText *self, + char ***attribute_names, + char ***attribute_values) +{ + *attribute_names = NULL; + *attribute_values = NULL; +} + static void gtk_accessible_text_default_init (GtkAccessibleTextInterface *iface) { @@ -71,6 +80,7 @@ gtk_accessible_text_default_init (GtkAccessibleTextInterface *iface) iface->get_caret_position = gtk_accessible_text_default_get_caret_position; iface->get_selection = gtk_accessible_text_default_get_selection; iface->get_attributes = gtk_accessible_text_default_get_attributes; + iface->get_default_attributes = gtk_accessible_text_default_get_default_attributes; } static GBytes * @@ -264,6 +274,41 @@ gtk_accessible_text_get_attributes (GtkAccessibleText *self, attribute_values); } +/*< private > + * gtk_accessible_text_get_default_attributes: + * @self: the accessible object + * @attribute_names: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full): + * the names of the attributes inside the accessible object + * @attribute_values: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full): + * the values of the attributes inside the accessible object + * + * Retrieves the default text attributes inside the accessible object. + * + * Each attribute is composed by: + * + * - a name, typically in the form of a reverse DNS identifier + * - a value + * + * If this function returns true, `n_attributes` will be set to a value + * greater than or equal to one, @ranges will be set to a newly + * allocated array of [struct#Gtk.AccessibleTextRange] which should + * be freed with g_free(), @attribute_names and @attribute_values + * will be set to string arrays that should be freed with g_strfreev(). + * + * Since: 4.14 + */ +void +gtk_accessible_text_get_default_attributes (GtkAccessibleText *self, + char ***attribute_names, + char ***attribute_values) +{ + g_return_if_fail (GTK_IS_ACCESSIBLE_TEXT (self)); + + GTK_ACCESSIBLE_TEXT_GET_IFACE (self)->get_default_attributes (self, + attribute_names, + attribute_values); +} + /** * gtk_accessible_text_update_caret_position: * @self: the accessible object diff --git a/gtk/gtkaccessibletext.h b/gtk/gtkaccessibletext.h index 5915f86c48..f4558a758e 100644 --- a/gtk/gtkaccessibletext.h +++ b/gtk/gtkaccessibletext.h @@ -228,6 +228,33 @@ struct _GtkAccessibleTextInterface GtkAccessibleTextRange **ranges, char ***attribute_names, char ***attribute_values); + + /** + * GtkAccessibleTextInterface::get_default_attributes: + * @self: the accessible object + * @attribute_names: (out) (array zero-terminated=1) (optional) (transfer full): the + * names of the default attributes inside the accessible object + * @attribute_values: (out) (array zero-terminated=1) (optional) (transfer full): the + * values of the default attributes inside the accessible object + * + * Retrieves the default text attributes inside the accessible object. + * + * Each attribute is composed by: + * + * - a name + * - a value + * + * It is left to the implementation to determine the serialization format + * of the value to a string. + * + * GTK provides support for various text attribute names and values, but + * implementations of this interface are free to add their own attributes. + * + * Since: 4.14 + */ + void (* get_default_attributes) (GtkAccessibleText *self, + char ***attribute_names, + char ***attribute_values); }; GDK_AVAILABLE_IN_4_14 diff --git a/gtk/gtkinscription.c b/gtk/gtkinscription.c index 78fb3c4c80..a5e5ecfbfc 100644 --- a/gtk/gtkinscription.c +++ b/gtk/gtkinscription.c @@ -1421,6 +1421,20 @@ gtk_inscription_accessible_text_get_attributes (GtkAccessibleText *self, return TRUE; } +static void +gtk_inscription_accessible_text_get_default_attributes (GtkAccessibleText *self, + char ***attribute_names, + char ***attribute_values) +{ + PangoLayout *layout = gtk_inscription_get_layout (GTK_INSCRIPTION (self)); + char **names, **values; + + gtk_pango_get_default_attributes (layout, &names, &values); + + *attribute_names = names; + *attribute_values = values; +} + static void gtk_inscription_accessible_text_init (GtkAccessibleTextInterface *iface) { @@ -1429,6 +1443,7 @@ gtk_inscription_accessible_text_init (GtkAccessibleTextInterface *iface) iface->get_caret_position = gtk_inscription_accessible_text_get_caret_position; iface->get_selection = gtk_inscription_accessible_text_get_selection; iface->get_attributes = gtk_inscription_accessible_text_get_attributes; + iface->get_default_attributes = gtk_inscription_accessible_text_get_default_attributes; } /* }}} */ diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index 7f9e1d7717..fc00253a69 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -6134,6 +6134,20 @@ gtk_label_accessible_text_get_selection (GtkAccessibleText *self, return TRUE; } +static void +gtk_label_accessible_text_get_default_attributes (GtkAccessibleText *self, + char ***attribute_names, + char ***attribute_values) +{ + PangoLayout *layout = gtk_label_get_layout (GTK_LABEL (self)); + char **names, **values; + + gtk_pango_get_default_attributes (layout, &names, &values); + + *attribute_names = names; + *attribute_values = values; +} + static gboolean gtk_label_accessible_text_get_attributes (GtkAccessibleText *self, unsigned int offset, @@ -6173,6 +6187,7 @@ gtk_label_accessible_text_init (GtkAccessibleTextInterface *iface) iface->get_caret_position = gtk_label_accessible_text_get_caret_position; iface->get_selection = gtk_label_accessible_text_get_selection; iface->get_attributes = gtk_label_accessible_text_get_attributes; + iface->get_default_attributes = gtk_label_accessible_text_get_default_attributes; } /* }}} */ diff --git a/gtk/gtktext.c b/gtk/gtktext.c index d3e151c1e0..6da0ecc9d7 100644 --- a/gtk/gtktext.c +++ b/gtk/gtktext.c @@ -7540,6 +7540,20 @@ gtk_text_accessible_text_get_attributes (GtkAccessibleText *self, return TRUE; } +static void +gtk_text_accessible_text_get_default_attributes (GtkAccessibleText *self, + char ***attribute_names, + char ***attribute_values) +{ + PangoLayout *layout = gtk_text_get_layout (GTK_TEXT (self)); + char **names, **values; + + gtk_pango_get_default_attributes (layout, &names, &values); + + *attribute_names = names; + *attribute_values = values; +} + static void gtk_text_accessible_text_init (GtkAccessibleTextInterface *iface) { @@ -7548,6 +7562,7 @@ gtk_text_accessible_text_init (GtkAccessibleTextInterface *iface) iface->get_caret_position = gtk_text_accessible_text_get_caret_position; iface->get_selection = gtk_text_accessible_text_get_selection; iface->get_attributes = gtk_text_accessible_text_get_attributes; + iface->get_default_attributes = gtk_text_accessible_text_get_default_attributes; } /* vim:set foldmethod=marker expandtab: */ diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c index 09bb01c7d5..16f8e7b953 100644 --- a/gtk/gtktextbuffer.c +++ b/gtk/gtktextbuffer.c @@ -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; } diff --git a/gtk/gtktextbufferprivate.h b/gtk/gtktextbufferprivate.h index 6e671f3e68..ee3ebcdbec 100644 --- a/gtk/gtktextbufferprivate.h +++ b/gtk/gtktextbufferprivate.h @@ -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 - diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 3dec1338c3..7473117635 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -10465,42 +10465,207 @@ 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; } +void +gtk_text_view_add_default_attributes (GtkTextView *view, + GHashTable *attributes) +{ + GtkTextAttributes *text_attrs; + PangoFontDescription *font; + + 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_hash_table_insert (attributes, + g_steal_pointer (&names[i]), + g_steal_pointer (&values[i])); + + g_free (names); + g_free (values); + } + +#define ADD_STR_ATTR(ht,name,value) \ + g_hash_table_insert ((ht), g_strdup ((name)), g_strdup ((value))) + +#define ADD_BOOL_ATTR(ht,name,value) \ + g_hash_table_insert ((ht), g_strdup ((name)), (value) ? g_strdup ("true") : g_strdup ("false")) + +#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 + +#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 + +#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 + + 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)); + + 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); + + ADD_COLOR_ATTR (attributes, "bg-color", text_attrs->appearance.bg_rgba); + ADD_COLOR_ATTR (attributes, "fg-color", text_attrs->appearance.fg_rgba); + + ADD_FLOAT_ATTR (attributes, "scale", text_attrs->font_scale); + + ADD_STR_ATTR (attributes, "language", (const char *) text_attrs->language); + + 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); + +#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) +{ + 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), attrs); + + n_attrs = g_hash_table_size (attrs); + if (n_attrs == 0) + { + g_hash_table_unref (attrs); + *attribute_names = NULL; + *attribute_values = NULL; + return; + } + + *attribute_names = g_new (char *, n_attrs + 1); + *attribute_values = g_new (char *, n_attrs + 1); + + i = 0; + g_hash_table_iter_init (&iter, attrs); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + (*attribute_names)[i] = g_strdup (key); + (*attribute_values)[i] = g_strdup (value); + + i += 1; + } + + (*attribute_names)[n_attrs] = NULL; + (*attribute_values)[n_attrs] = NULL; + + g_hash_table_unref (attrs); +} + static void gtk_text_view_accessible_text_init (GtkAccessibleTextInterface *iface) { @@ -10509,6 +10674,7 @@ gtk_text_view_accessible_text_init (GtkAccessibleTextInterface *iface) iface->get_caret_position = gtk_text_view_accessible_text_get_caret_position; iface->get_selection = gtk_text_view_accessible_text_get_selection; iface->get_attributes = gtk_text_view_accessible_text_get_attributes; + iface->get_default_attributes = gtk_text_view_accessible_text_get_default_attributes; } /* }}} */ diff --git a/gtk/gtktextviewprivate.h b/gtk/gtktextviewprivate.h index 2c88e1d112..dd472f7656 100644 --- a/gtk/gtktextviewprivate.h +++ b/gtk/gtktextviewprivate.h @@ -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 diff --git a/testsuite/gtk/textbuffer.c b/testsuite/gtk/textbuffer.c index 1a81267359..66a46ade2f 100644 --- a/testsuite/gtk/textbuffer.c +++ b/testsuite/gtk/textbuffer.c @@ -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);