gtkbuilder: add accessibility role declaration
authorSamuel Thibault <samuel.thibault@ens-lyon.org>
Mon, 19 Mar 2018 13:11:16 +0000 (14:11 +0100)
committerSamuel Thibault <samuel.thibault@ens-lyon.org>
Mon, 19 Mar 2018 17:07:06 +0000 (18:07 +0100)
This allows to override the role declared to the atk stack.  For
instance,

<accessibility>
  <role type="static"/>
</accessibility>

allows to tell the accessibility stack that a label is just a message in
a message box.

Fixes #109

demos/gtk-demo/listbox.ui
demos/widget-factory/widget-factory.ui
gtk/gtkwidget.c
testsuite/a11y/label-static.txt [new file with mode: 0644]
testsuite/a11y/label-static.ui [new file with mode: 0644]
testsuite/gtk/builder.c

index 76b49b285d4bf99e73dd523f027e786efa0d39de..606a5202246cbd5a23f936238068989b9574ca9a 100644 (file)
@@ -98,6 +98,9 @@
             <property name="yalign">0</property>
             <property name="label" translatable="0">Message</property>
             <property name="wrap">1</property>
+            <accessibility>
+              <role type="static"/>
+            </accessibility>
           </object>
           <packing>
             <property name="left-attach">1</property>
index 8474d08d76bcba73e313b868e924ea1962d9d8e3..f8ab748010096f15ad45ca5df960f992f5223918 100644 (file)
@@ -3274,6 +3274,9 @@ bad things might happen.</property>
           <object class="GtkLabel">
             <property name="margin">20</property>
             <property name="label" translatable="yes">To free the princess, you have to slay the dragon.</property>
+            <accessibility>
+              <role type="static"/>
+            </accessibility>
           </object>
         </child>
       </object>
@@ -3551,6 +3554,9 @@ bad things might happen.</property>
     <child>
       <object class="GtkLabel" id="notebook_info_label">
         <property name="label">No updates at this time</property>
+        <accessibility>
+          <role type="static"/>
+        </accessibility>
       </object>
     </child>
   </object>
index 902894bec8a19b7ebc7a2273a018a00b416a28b9..f78add8c09111243e5153d7e4897907a0f4222b2 100644 (file)
@@ -10685,6 +10685,7 @@ typedef struct
   GtkBuilder *builder;
   GSList *actions;
   GSList *relations;
+  AtkRole role;
 } AccessibilitySubParserData;
 
 static void
@@ -10764,6 +10765,45 @@ accessibility_start_element (GMarkupParseContext  *context,
 
       data->actions = g_slist_prepend (data->actions, action);
     }
+  else if (strcmp (element_name, "role") == 0)
+    {
+      const gchar *type;
+      AtkRole role;
+
+      if (!_gtk_builder_check_parent (data->builder, context, "accessibility", error))
+        return;
+
+      if (data->role != ATK_ROLE_INVALID)
+        {
+          g_set_error (error,
+                       GTK_BUILDER_ERROR,
+                       GTK_BUILDER_ERROR_INVALID_VALUE,
+                       "Duplicate accessibility role definition");
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      if (!g_markup_collect_attributes (element_name, names, values, error,
+                                        G_MARKUP_COLLECT_STRING, "type", &type,
+                                        G_MARKUP_COLLECT_INVALID))
+        {
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      role = atk_role_for_name (type);
+      if (role == ATK_ROLE_INVALID)
+        {
+          g_set_error (error,
+                       GTK_BUILDER_ERROR,
+                       GTK_BUILDER_ERROR_INVALID_VALUE,
+                       "No such role type: '%s'", type);
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      data->role = role;
+    }
   else if (strcmp (element_name, "accessibility") == 0)
     {
       if (!_gtk_builder_check_parent (data->builder, context, "object", error))
@@ -11108,6 +11148,12 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
        g_object_set_qdata (G_OBJECT (buildable), quark_builder_atk_relations,
                            a11y_data->relations);
 
+      if (a11y_data->role != ATK_ROLE_INVALID)
+        {
+          AtkObject *accessible = gtk_widget_get_accessible (GTK_WIDGET (buildable));
+          atk_object_set_role (accessible, a11y_data->role);
+        }
+
       g_slice_free (AccessibilitySubParserData, a11y_data);
     }
   else if (strcmp (tagname, "style") == 0)
diff --git a/testsuite/a11y/label-static.txt b/testsuite/a11y/label-static.txt
new file mode 100644 (file)
index 0000000..cfffa4c
--- /dev/null
@@ -0,0 +1,75 @@
+window1
+  "window"
+  index: 0
+  state: enabled resizable sensitive showing visible
+  toolkit: gtk
+  window-type: normal
+  <AtkComponent>
+  layer: window
+  alpha: 1
+  label1
+    "static"
+    parent: window1
+    index: 0
+    name: Go to the GTK+ website or >google it
+    state: enabled focusable multi-line sensitive has-tooltip
+    toolkit: gtk
+    <AtkComponent>
+    layer: widget
+    alpha: 1
+    <AtkText>
+    text: Go to the GTK+ website or >google it
+    character count: 36
+    caret offset: 0
+    default attributes: bg-color: <omitted>
+                        bg-full-height: 0
+                        direction: <omitted>
+                        editable: false
+                        family-name: <omitted>
+                        fg-color: <omitted>
+                        indent: 0
+                        invisible: false
+                        justification: left
+                        language: <omitted>
+                        left-margin: 0
+                        pixels-above-lines: 0
+                        pixels-below-lines: 0
+                        pixels-inside-wrap: 0
+                        right-margin: 0
+                        rise: 0
+                        scale: 1
+                        size: <omitted>
+                        stretch: <omitted>
+                        strikethrough: false
+                        style: <omitted>
+                        underline: none
+                        variant: <omitted>
+                        weight: <omitted>
+                        wrap-mode: word
+    <AtkHypertext>
+      <AtkHyperlink>
+      start index: 10
+      end index: 22
+      anchors: http://www.gtk.org
+      <AtkHyperlink>
+      start index: 27
+      end index: 36
+      anchors: http://www.google.com
+    unnamed-GtkLabelAccessibleLinkImpl-0
+      "link"
+      parent: label1
+      state: enabled focusable multi-line sensitive has-tooltip
+      <AtkHyperlinkImpl>
+        <AtkHyperlink>
+        start index: 10
+        end index: 22
+        anchors: http://www.gtk.org
+    unnamed-GtkLabelAccessibleLinkImpl-1
+      "link"
+      parent: label1
+      state: enabled focusable multi-line sensitive has-tooltip
+      <AtkHyperlinkImpl>
+        <AtkHyperlink>
+        start index: 27
+        end index: 36
+        anchors: http://www.google.com
diff --git a/testsuite/a11y/label-static.ui b/testsuite/a11y/label-static.ui
new file mode 100644 (file)
index 0000000..1e478c0
--- /dev/null
@@ -0,0 +1,17 @@
+
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkWindow" id="window1">
+    <property name="can_focus">False</property>
+    <property name="type">popup</property>
+    <child>
+      <object class="GtkLabel" id="label1">
+        <property name="label">Go to the &lt;a href="http://www.gtk.org" title="&lt;i&gt;Our&lt;/i&gt; website"&gt;GTK+ website&lt;/a&gt; or &lt;small&gt;&gt;&lt;a href="http://www.google.com"&gt;google it&lt;/a&gt;&lt;/small&gt;</property>
+        <property name="use-markup">True</property>
+        <accessibility>
+          <role type="static"/>
+        </accessibility>
+      </object>
+    </child>
+  </object>
+</interface>
index 9d5fb822f363bb16a78ed87371401ff8ecda9d98..e662570a2672fb66229dafe87be1cbc5a6a2a564 100644 (file)
@@ -1520,6 +1520,20 @@ test_widget (void)
     "    </child>"
     "  </object>"
     "</interface>";
+  const gchar *buffer4 =
+    "<interface>"
+    "  <object class=\"GtkWindow\" id=\"window1\">"
+    "    <child>"
+    "      <object class=\"GtkLabel\" id=\"label1\">"
+    "         <property name=\"label\">Thelabel</property>"
+    "         <property name=\"can_focus\">False</property>"
+    "         <accessibility>"
+    "            <role type=\"static\"/>"
+    "         </accessibility>"
+    "      </object>"
+    "    </child>"
+    "  </object>"
+   "</interface>";
   GtkBuilder *builder;
   GObject *window1, *button1, *label1;
   AtkObject *accessible;
@@ -1565,6 +1579,14 @@ test_widget (void)
   
   gtk_widget_destroy (GTK_WIDGET (window1));
   g_object_unref (builder);
+
+  builder = builder_new_from_string (buffer4, -1, NULL);
+  label1 = gtk_builder_get_object (builder, "label1");
+
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (label1));
+  g_assert (atk_object_get_role (accessible) == ATK_ROLE_STATIC);
+
+  g_object_unref (builder);
 }
 
 static void