gtk+ r19407 - in branches/gtk-2-12: . docs/reference docs/reference/gtk/tmpl gtk tests



Author: johan
Date: Fri Jan 25 19:52:15 2008
New Revision: 19407
URL: http://svn.gnome.org/viewvc/gtk+?rev=19407&view=rev

Log:
2008-01-25  Johan Dahlin  <johan gnome org>

	Merge from trunk:

	* gtk/gtk-builder-convert
	(GtkBuilderConverter._convert_adjustment): Handle the case where
	there is no child text node.
	(GtkBuilderConverter): Allow xml comments in most places.

	* gtk/gtk-builder-convert
	(GtkBuilderConverter._convert_combobox_items): Remove the items
	even if there are no items set.
	(GtkBuilderConverter._add_action_from_menuitem): Convert toggled
	signals and tooltips for all menu items subclasses and 
	GtkImageMenuItem:label. 
	Makes it possible to fully convert and run Jokosher.glade.

	* gtk/gtkwidget.c: (gtk_widget_buildable_interface_init),
	(gtk_widget_buildable_get_internal_child), (free_action),
	(free_relation), (gtk_widget_buildable_parser_finished),
	(accessibility_start_element),
	(gtk_widget_buildable_custom_tag_start),
	(gtk_widget_buildable_custom_finished):
	Implement accessible support, fixes #454653.

	* gtk/gtk-builder-convert:
	Add support for migrating old glade files
	
	* tests/buildertest.c: (test_widget), (test_file):
	Add accessible tests and imprve the test_file function to display
	toplevels and run dialogs.



Modified:
   branches/gtk-2-12/ChangeLog
   branches/gtk-2-12/docs/reference/ChangeLog
   branches/gtk-2-12/docs/reference/gtk/tmpl/gtkwidget.sgml
   branches/gtk-2-12/gtk/gtk-builder-convert
   branches/gtk-2-12/gtk/gtkwidget.c
   branches/gtk-2-12/tests/buildertest.c

Modified: branches/gtk-2-12/docs/reference/gtk/tmpl/gtkwidget.sgml
==============================================================================
--- branches/gtk-2-12/docs/reference/gtk/tmpl/gtkwidget.sgml	(original)
+++ branches/gtk-2-12/docs/reference/gtk/tmpl/gtkwidget.sgml	Fri Jan 25 19:52:15 2008
@@ -37,6 +37,31 @@
 </object>
 ]]></programlisting>
 </example>
+In addition to accelerators, <structname>GtkWidget</structname> also support a 
+custom &lt;accessible&gt; element, which supports actions and relations. 
+Properties on the accessible implementation of an object can be set by accessing the 
+internal child "accessible" of a <structname>GtkWidget</structname>.
+<example>
+<title>A UI definition fragment specifying an accessible</title>
+<programlisting><![CDATA[
+<object class="GtkButton" id="label1"/>
+  <property name="label">I am a Label for a Button</property>
+</object>
+<object class="GtkButton" id="button1">
+  <accessibility>
+    <action action_name="click" description="Click the button."/>
+    <relation target="label1" type="labelled-by"/>
+  </accessibility>
+  <child internal-child="accessible">
+    <object class="AtkObject" id="a11y-button1">
+      <property name="AtkObject::name">Clickable Button</property>
+    </object>
+  </child>
+</object>
+]]></programlisting>
+</example>
+
+
 </refsect2>
 
 <!-- ##### SECTION See_Also ##### -->

Modified: branches/gtk-2-12/gtk/gtk-builder-convert
==============================================================================
--- branches/gtk-2-12/gtk/gtk-builder-convert	(original)
+++ branches/gtk-2-12/gtk/gtk-builder-convert	Fri Jan 25 19:52:15 2008
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright (C) 2006-2007 Async Open Source
+# Copyright (C) 2006-2008 Async Open Source
 #                         Henrique Romano <henrique async com br>
 #                         Johan Dahlin <jdahlin async com br>
 #
@@ -58,7 +58,7 @@
     assert node.tagName == 'object'
     nodes = []
     for child in node.childNodes:
-        if child.nodeType == Node.TEXT_NODE:
+        if child.nodeType != Node.ELEMENT_NODE:
             continue
         if child.tagName != 'child':
             continue
@@ -69,7 +69,7 @@
     assert node.tagName == 'object'
     properties = {}
     for child in node.childNodes:
-        if child.nodeType == Node.TEXT_NODE:
+        if child.nodeType != Node.ELEMENT_NODE:
             continue
         if child.tagName != 'property':
             continue
@@ -86,7 +86,7 @@
     assert node.tagName == 'object'
     properties = {}
     for child in node.childNodes:
-        if child.nodeType == Node.TEXT_NODE:
+        if child.nodeType != Node.ELEMENT_NODE:
             continue
         if child.tagName != 'property':
             continue
@@ -97,7 +97,7 @@
     assert node.tagName == 'object'
     signals = []
     for child in node.childNodes:
-        if child.nodeType == Node.TEXT_NODE:
+        if child.nodeType != Node.ELEMENT_NODE:
             continue
         if child.tagName == 'signal':
             signals.append(child)
@@ -107,8 +107,9 @@
     assert node.tagName == 'object'
     properties = []
     for child in node.childNodes:
-        if child.nodeType == Node.TEXT_NODE:
+        if child.nodeType != Node.ELEMENT_NODE:
             continue
+        # FIXME: handle comments
         if child.tagName == 'property':
             properties.append(child)
     return properties
@@ -117,17 +118,17 @@
     assert node.tagName == 'object'
     accelerators = []
     for child in node.childNodes:
-        if child.nodeType == Node.TEXT_NODE:
+        if child.nodeType != Node.ELEMENT_NODE:
             continue
         if child.tagName == 'accelerator':
             accelerators.append(child)
     return accelerators
 
 def get_object_node(child_node):
-    assert child_node.tagName == 'child'
+    assert child_node.tagName == 'child', child_node
     nodes = []
     for node in child_node.childNodes:
-        if node.nodeType == Node.TEXT_NODE:
+        if node.nodeType != Node.ELEMENT_NODE:
             continue
         if node.tagName == 'object':
             nodes.append(node)
@@ -178,7 +179,7 @@
         return [w for w in self._dom.getElementsByTagName("object")
                       if w.getAttribute(attribute) == value]
 
-    def _create_object(self, obj_class, obj_id, template=None, **properties):
+    def _create_object(self, obj_class, obj_id, template=None, properties=None):
         """
         Creates a new <object> tag.
         Optionally a name template can be provided which will be used
@@ -207,22 +208,23 @@
         obj = self._dom.createElement('object')
         obj.setAttribute('class', obj_class)
         obj.setAttribute('id', obj_id)
-        for name, value in properties.items():
-            if isinstance(value, Node):
-                # Reuse the node, so translatable and context still will be
-                # set when converting nodes. See also #509153
-                prop = value
-            else:
-                prop = self._dom.createElement('property')
-                prop.appendChild(self._dom.createTextNode(value))
+        if properties:
+            for name, value in properties.items():
+                if isinstance(value, Node):
+                    # Reuse the node, so translatable and context still will be
+                    # set when converting nodes. See also #509153
+                    prop = value
+                else:
+                    prop = self._dom.createElement('property')
+                    prop.appendChild(self._dom.createTextNode(value))
 
-            prop.setAttribute('name', name)
-            obj.appendChild(prop)
+                prop.setAttribute('name', str(name))
+                obj.appendChild(prop)
         self.objects[obj_id] = obj
         return obj
 
-    def _create_root_object(self, obj_class, template, **properties):
-        obj = self._create_object(obj_class, None, template, **properties)
+    def _create_root_object(self, obj_class, template, properties=None):
+        obj = self._create_object(obj_class, None, template, properties)
         self.root_objects.append(obj)
         return obj
 
@@ -261,6 +263,10 @@
         for node in self._dom.getElementsByTagName("ui"):
             self._convert_ui(node)
 
+        # Convert accessibility tag
+        for node in self._dom.getElementsByTagName("accessibility"):
+            self._convert_accessibility(node)
+
         # Output the newly created root objects and sort them
         # by attribute id
         for obj in sorted(self.root_objects,
@@ -376,7 +382,7 @@
         return menu
 
     def _menuitem_to_action(self, node, properties):
-        copy_properties(node, ['label'], properties)
+        copy_properties(node, ['label', 'tooltip'], properties)
 
     def _togglemenuitem_to_action(self, node, properties):
         self._menuitem_to_action(node, properties)
@@ -408,6 +414,7 @@
                 child = get_property_node(image, 'stock')
                 if child is not None:
                     properties['stock_id'] = child
+            self._menuitem_to_action(node, properties)
         elif object_class == 'GtkSeparatorMenuItem':
             return
         else:
@@ -421,11 +428,11 @@
         properties['name'] = object_id
         action = self._create_object(name,
                                      object_id,
-                                     **properties)
+                                     properties=properties)
 
         for signal in get_signal_nodes(node):
             signal_name = signal.getAttribute('name')
-            if signal_name == 'activate':
+            if signal_name in ['activate', 'toggled']:
                 action.appendChild(signal)
             else:
                 print 'Unhandled signal %s::%s' % (node.getAttribute('class'),
@@ -494,7 +501,7 @@
 
         # 2) Get dialogs action-widgets tag, create if not found
         for child in dialog.childNodes:
-            if child.nodeType == Node.TEXT_NODE:
+            if child.nodeType != Node.ELEMENT_NODE:
                 continue
             if child.tagName == 'action-widgets':
                 actions = child
@@ -510,20 +517,28 @@
         actions.appendChild(action)
 
     def _convert_adjustment(self, prop):
-        data = prop.childNodes[0].data
-        value, lower, upper, step, page, page_size = data.split(' ')
+        properties = {}
+        if prop.childNodes:
+            data = prop.childNodes[0].data
+            value, lower, upper, step, page, page_size = data.split(' ')
+            properties.update(value=value,
+                              lower=lower,
+                              upper=upper,
+                              step_increment=step,
+                              page_increment=page,
+                              page_size=page_size)
+        else:
+            prop.appendChild(self._dom.createTextNode(""))
+
         adj = self._create_root_object("GtkAdjustment",
                                        template='adjustment',
-                                       value=value,
-                                       lower=lower,
-                                       upper=upper,
-                                       step_increment=step,
-                                       page_increment=page,
-                                       page_size=page_size)
+                                       properties=properties)
         prop.childNodes[0].data = adj.getAttribute('id')
 
     def _convert_combobox_items(self, node, prop):
+        parent = prop.parentNode
         if not prop.childNodes:
+            parent.removeChild(prop)
             return
         value = prop.childNodes[0].data
         model = self._create_root_object("GtkListStore",
@@ -548,7 +563,6 @@
             col.appendChild(self._dom.createTextNode(item))
             row.appendChild(col)
 
-        parent = prop.parentNode
         model_prop = self._dom.createElement('property')
         model_prop.setAttribute('name', 'model')
         model_prop.appendChild(
@@ -581,7 +595,7 @@
             prop.removeAttribute('translatable')
         tbuffer = self._create_root_object("GtkTextBuffer",
                                            template='textbuffer',
-                                           text=data)
+                                           properties=dict(text=data))
         prop.childNodes[0].data = tbuffer.getAttribute('id')
 
     def _packing_prop_to_child_attr(self, node, prop_name, prop_val,
@@ -623,6 +637,35 @@
             widget.getAttributeNode("constructor").value = parent_id
         node.removeAttribute("id")
 
+    def _convert_accessibility(self, node):
+        objectNode = node.parentNode
+        parent_id = objectNode.getAttribute("id")
+
+        properties = {}
+        for node in node.childNodes:
+            if node.nodeName == 'atkproperty':
+                node.tagName = 'property'
+                properties[node.getAttribute('name')] = node
+                node.parentNode.removeChild(node)
+            elif node.nodeName == 'atkrelation':
+                node.tagName = 'relation'
+                relation_type = node.getAttribute('type')
+                relation_type = relation_type.replace('_', '-')
+                node.setAttribute('type', relation_type)
+            elif node.nodeName == 'atkaction':
+                node.tagName = 'action'
+
+        if properties:
+            child = self._dom.createElement('child')
+            child.setAttribute("internal-child", "accessible")
+
+            atkobject = self._create_object(
+                "AtkObject", None,
+                template='a11y-%s' % (parent_id,),
+                properties=properties)
+            child.appendChild(atkobject)
+            objectNode.appendChild(child)
+
     def _strip_root(self, root_name):
         for widget in self._dom.getElementsByTagName("widget"):
             if widget.getAttribute('id') == root_name:

Modified: branches/gtk-2-12/gtk/gtkwidget.c
==============================================================================
--- branches/gtk-2-12/gtk/gtkwidget.c	(original)
+++ branches/gtk-2-12/gtk/gtkwidget.c	Fri Jan 25 19:52:15 2008
@@ -251,6 +251,9 @@
 static void             gtk_widget_buildable_set_name           (GtkBuildable     *buildable,
                                                                  const gchar      *name);
 static const gchar *    gtk_widget_buildable_get_name           (GtkBuildable     *buildable);
+static GObject *        gtk_widget_buildable_get_internal_child (GtkBuildable *buildable,
+								 GtkBuilder   *builder,
+								 const gchar  *childname);
 static void             gtk_widget_buildable_set_buildable_property (GtkBuildable     *buildable,
 								     GtkBuilder       *builder,
 								     const gchar      *name,
@@ -8847,17 +8850,20 @@
 /*
  * GtkBuildable implementation
  */
-static GQuark		quark_builder_has_default = 0;
-static GQuark		quark_builder_has_focus = 0;
+static GQuark		 quark_builder_has_default = 0;
+static GQuark		 quark_builder_has_focus = 0;
+static GQuark		 quark_builder_atk_relations = 0;
 
 static void
 gtk_widget_buildable_interface_init (GtkBuildableIface *iface)
 {
   quark_builder_has_default = g_quark_from_static_string ("gtk-builder-has-default");
   quark_builder_has_focus = g_quark_from_static_string ("gtk-builder-has-focus");
+  quark_builder_atk_relations = g_quark_from_static_string ("gtk-builder-atk-relations");
 
   iface->set_name = gtk_widget_buildable_set_name;
   iface->get_name = gtk_widget_buildable_get_name;
+  iface->get_internal_child = gtk_widget_buildable_get_internal_child;
   iface->set_buildable_property = gtk_widget_buildable_set_buildable_property;
   iface->parser_finished = gtk_widget_buildable_parser_finished;
   iface->custom_tag_start = gtk_widget_buildable_custom_tag_start;
@@ -8877,6 +8883,17 @@
   return gtk_widget_get_name (GTK_WIDGET (buildable));
 }
 
+static GObject *
+gtk_widget_buildable_get_internal_child (GtkBuildable *buildable,
+					 GtkBuilder   *builder,
+					 const gchar  *childname)
+{
+  if (strcmp (childname, "accessible") == 0)
+    return G_OBJECT (gtk_widget_get_accessible (GTK_WIDGET (buildable)));
+
+  return NULL;
+}
+
 static void
 gtk_widget_buildable_set_buildable_property (GtkBuildable *buildable,
 					     GtkBuilder   *builder,
@@ -8893,17 +8910,224 @@
     g_object_set_property (G_OBJECT (buildable), name, value);
 }
 
+typedef struct {
+  gchar *action_name;
+  gchar *description;
+} AtkActionData;
+  
+typedef struct {
+  gchar *target;
+  gchar *type;
+} AtkRelationData;
+
+static void
+free_action (AtkActionData *data, gpointer user_data)
+{
+  g_free (data->action_name);
+  g_free (data->description);
+  g_slice_free (AtkActionData, data);
+}
+
+static void
+free_relation (AtkRelationData *data, gpointer user_data)
+{
+  g_free (data->target);
+  g_free (data->type);
+  g_slice_free (AtkRelationData, data);
+}
+
 static void
 gtk_widget_buildable_parser_finished (GtkBuildable *buildable,
 				      GtkBuilder   *builder)
 {
+  GSList *atk_relations;
+  
   if (g_object_get_qdata (G_OBJECT (buildable), quark_builder_has_default))
     gtk_widget_grab_default (GTK_WIDGET (buildable));
   if (g_object_get_qdata (G_OBJECT (buildable), quark_builder_has_focus))
     gtk_widget_grab_focus (GTK_WIDGET (buildable));
+
+  atk_relations = g_object_get_qdata (G_OBJECT (buildable),
+				      quark_builder_atk_relations);
+  if (atk_relations)
+    {
+      AtkObject *accessible;
+      AtkRelationSet *relation_set;
+      GSList *l;
+      GObject *target;
+      AtkRelationType relation_type;
+      AtkObject *target_accessible;
+      
+      accessible = gtk_widget_get_accessible (GTK_WIDGET (buildable));
+      relation_set = atk_object_ref_relation_set (accessible);
+
+      for (l = atk_relations; l; l = l->next)
+	{
+	  AtkRelationData *relation = (AtkRelationData*)l->data;
+	  
+	  target = gtk_builder_get_object (builder, relation->target);
+	  if (!target)
+	    {
+	      g_warning ("Target object %s in <relation> does not exist",
+			 relation->target);
+	      continue;
+	    }
+	  target_accessible = gtk_widget_get_accessible (GTK_WIDGET (target));
+	  g_assert (target_accessible != NULL);
+	  
+	  relation_type = atk_relation_type_for_name (relation->type);
+	  if (relation_type == ATK_RELATION_NULL)
+	    {
+	      g_warning ("<relation> type %s not found",
+			 relation->type);
+	      continue;
+	    }
+	  atk_relation_set_add_relation_by_type (relation_set, relation_type,
+						 target_accessible);
+	}
+      g_object_unref (relation_set);
+
+      g_slist_foreach (atk_relations, (GFunc)free_relation, NULL);
+      g_slist_free (atk_relations);
+      g_object_set_qdata (G_OBJECT (buildable), quark_builder_atk_relations,
+			  NULL);
+    }
+    
 }
 
 typedef struct {
+  GSList *actions;
+  GSList *relations;
+} AccessibilitySubParserData;
+
+static void
+accessibility_start_element (GMarkupParseContext *context,
+			     const gchar         *element_name,
+			     const gchar        **names,
+			     const gchar        **values,
+			     gpointer             user_data,
+			     GError             **error)
+{
+  AccessibilitySubParserData *data = (AccessibilitySubParserData*)user_data;
+  guint i;
+  gint line_number, char_number;
+
+  if (strcmp (element_name, "relation") == 0)
+    {
+      gchar *target = NULL;
+      gchar *type = NULL;
+      AtkRelationData *relation;
+      
+      for (i = 0; names[i]; i++)
+	{
+	  if (strcmp (names[i], "target") == 0)
+	    target = g_strdup (values[i]);
+	  else if (strcmp (names[i], "type") == 0)
+	    type = g_strdup (values[i]);
+	  else
+	    {
+	      g_markup_parse_context_get_position (context,
+						   &line_number,
+						   &char_number);
+	      g_set_error (error,
+			   GTK_BUILDER_ERROR,
+			   GTK_BUILDER_ERROR_INVALID_ATTRIBUTE,
+			   "%s:%d:%d '%s' is not a valid attribute of <%s>",
+			   "<input>",
+			   line_number, char_number, names[i], "relation");
+	      g_free (target);
+	      g_free (type);
+	      return;
+	    }
+	}
+
+      if (!target || !type)
+	{
+	  g_markup_parse_context_get_position (context,
+					       &line_number,
+					       &char_number);
+	  g_set_error (error,
+		       GTK_BUILDER_ERROR,
+		       GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
+		       "%s:%d:%d <%s> requires attribute \"%s\"",
+		       "<input>",
+		       line_number, char_number, "relation",
+		       type ? "target" : "type");
+	  g_free (target);
+	  g_free (type);
+	  return;
+	}
+
+      relation = g_slice_new (AtkRelationData);
+      relation->target = target;
+      relation->type = type;
+      
+      data->relations = g_slist_prepend (data->relations, relation);
+    }
+  else if (strcmp (element_name, "action") == 0)
+    {
+      gchar *action_name = NULL;
+      gchar *description = NULL;
+      AtkActionData *action;
+      
+      for (i = 0; names[i]; i++)
+	{
+	  if (strcmp (names[i], "action_name") == 0)
+	    action_name = g_strdup (values[i]);
+	  else if (strcmp (names[i], "description") == 0)
+	    description = g_strdup (values[i]);
+	  else
+	    {
+	      g_markup_parse_context_get_position (context,
+						   &line_number,
+						   &char_number);
+	      g_set_error (error,
+			   GTK_BUILDER_ERROR,
+			   GTK_BUILDER_ERROR_INVALID_ATTRIBUTE,
+			   "%s:%d:%d '%s' is not a valid attribute of <%s>",
+			   "<input>",
+			   line_number, char_number, names[i], "action");
+	      g_free (action_name);
+	      g_free (description);
+	      return;
+	    }
+	}
+
+      if (!action_name || !description)
+	{
+	  g_markup_parse_context_get_position (context,
+					       &line_number,
+					       &char_number);
+	  g_set_error (error,
+		       GTK_BUILDER_ERROR,
+		       GTK_BUILDER_ERROR_MISSING_ATTRIBUTE,
+		       "%s:%d:%d <%s> requires attribute \"%s\"",
+		       "<input>",
+		       line_number, char_number, "action",
+		       description ? "action_name" : "description");
+	  g_free (action_name);
+	  g_free (description);
+	  return;
+	}
+
+      action = g_slice_new (AtkActionData);
+      action->action_name = action_name;
+      action->description = description;
+      
+      data->actions = g_slist_prepend (data->actions, action);
+    }
+  else if (strcmp (element_name, "accessibility") == 0)
+    ;
+  else
+    g_warning ("Unsupported tag for GtkWidget: %s\n", element_name);
+}
+
+static const GMarkupParser accessibility_parser =
+  {
+    accessibility_start_element,
+  };
+
+typedef struct {
   GObject *object;
   guint    key;
   guint    modifiers;
@@ -8955,12 +9179,6 @@
     accel_group_start_element,
   };
 
-static const GMarkupParser accessibility_parser =
-  {
-    NULL,
-  };
-
-
 static gboolean
 gtk_widget_buildable_custom_tag_start (GtkBuildable     *buildable,
 				       GtkBuilder       *builder,
@@ -8969,31 +9187,25 @@
 				       GMarkupParser    *parser,
 				       gpointer         *data)
 {
-  AccelGroupParserData *parser_data;
-
   g_assert (buildable);
 
   if (strcmp (tagname, "accelerator") == 0)
     {
+      AccelGroupParserData *parser_data;
+
       parser_data = g_slice_new0 (AccelGroupParserData);
       parser_data->object = g_object_ref (buildable);
       *parser = accel_group_parser;
       *data = parser_data;
       return TRUE;
     }
-  else if (strcmp (tagname, "accessibility") == 0)
+  if (strcmp (tagname, "accessibility") == 0)
     {
-      static gboolean warning_showed = FALSE;
-
-      if (!warning_showed)
-	{
-	  g_warning ("<accessibility> is being ignored,\n"
-		     "see http://bugzilla.gnome.org/show_bug.cgi?id=454653\n";);
-	  warning_showed = TRUE;
-	}
+      AccessibilitySubParserData *parser_data;
 
+      parser_data = g_slice_new0 (AccessibilitySubParserData);
       *parser = accessibility_parser;
-      *data = NULL;
+      *data = parser_data;
       return TRUE;
     }
   return FALSE;
@@ -9006,17 +9218,18 @@
 				      const gchar  *tagname,
 				      gpointer      user_data)
 {
-  AccelGroupParserData *data;
+  AccelGroupParserData *accel_data;
+  AccessibilitySubParserData *a11y_data;
   GtkWidget *toplevel;
   GSList *accel_groups;
   GtkAccelGroup *accel_group;
 
   if (strcmp (tagname, "accelerator") == 0)
     {
-      data = (AccelGroupParserData*)user_data;
-      g_assert (data->object);
+      accel_data = (AccelGroupParserData*)user_data;
+      g_assert (accel_data->object);
 
-      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (data->object));
+      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (accel_data->object));
       accel_groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
       if (g_slist_length (accel_groups) == 0)
 	{
@@ -9028,15 +9241,56 @@
 	  g_assert (g_slist_length (accel_groups) == 1);
 	  accel_group = g_slist_nth_data (accel_groups, 0);
 	}
-      gtk_widget_add_accelerator (GTK_WIDGET(data->object),
-				  data->signal,
+      gtk_widget_add_accelerator (GTK_WIDGET (accel_data->object),
+				  accel_data->signal,
 				  accel_group,
-				  data->key,
-				  data->modifiers,
+				  accel_data->key,
+				  accel_data->modifiers,
 				  GTK_ACCEL_VISIBLE);
-      g_object_unref (data->object);
-      g_free (data->signal);
-      g_slice_free (AccelGroupParserData, data);
+      g_object_unref (accel_data->object);
+      g_free (accel_data->signal);
+      g_slice_free (AccelGroupParserData, accel_data);
+    }
+  else if (strcmp (tagname, "accessibility") == 0)
+    {
+      a11y_data = (AccessibilitySubParserData*)user_data;
+
+      if (a11y_data->actions)
+	{
+	  AtkObject *accessible;
+	  AtkAction *action;
+	  gint i, n_actions;
+	  GSList *l;
+	  
+	  accessible = gtk_widget_get_accessible (GTK_WIDGET (buildable));
+	  
+	  action = ATK_ACTION (accessible);
+	  n_actions = atk_action_get_n_actions (action);    
+	  
+	  for (l = a11y_data->actions; l; l = l->next)
+	    {
+	      AtkActionData *action_data = (AtkActionData*)l->data;
+	      
+	      for (i = 0; i < n_actions; i++)
+		if (strcmp (atk_action_get_name (action, i),
+			    action_data->action_name) == 0)
+		  break;
+
+	      if (i < n_actions)
+		atk_action_set_description (action, i,
+					    action_data->description);
+	    }
+	  
+	  g_slist_foreach (a11y_data->actions, (GFunc)free_action, NULL);
+	  g_slist_free (a11y_data->actions);
+	}
+
+      if (a11y_data->relations)
+	g_object_set_qdata (G_OBJECT (buildable), quark_builder_atk_relations,
+			    a11y_data->relations);
+      
+      g_slice_free (AccessibilitySubParserData, a11y_data);
+      
     }
 }
 

Modified: branches/gtk-2-12/tests/buildertest.c
==============================================================================
--- branches/gtk-2-12/tests/buildertest.c	(original)
+++ branches/gtk-2-12/tests/buildertest.c	Fri Jan 25 19:52:15 2008
@@ -1485,14 +1485,37 @@
   gchar *buffer3 =
     "<interface>"
     "  <object class=\"GtkWindow\" id=\"window1\">"
-    "     <accessibility>"
-    "       <atkproperty name=\"AtkObject::accessible_name\" translatable=\"yes\">Contacts</atkproperty>"
-    "       <atkrelation target=\"button1\" type=\"labelled-by\"/>"
-    "     </accessibility>"
+    "    <child>"
+    "      <object class=\"GtkVBox\" id=\"vbox1\">"
+    "        <child>"
+    "          <object class=\"GtkLabel\" id=\"label1\">"
+    "            <child internal-child=\"accessible\">"
+    "              <object class=\"AtkObject\" id=\"a11y-label1\">"
+    "                <property name=\"AtkObject::accessible-name\">A Label</property>"
+    "              </object>"
+    "            </child>"
+    "            <accessibility>"
+    "              <relation target=\"button1\" type=\"label-for\"/>"
+    "            </accessibility>"
+    "          </object>"
+    "        </child>"
+    "        <child>"
+    "          <object class=\"GtkButton\" id=\"button1\">"
+    "            <accessibility>"
+    "              <action action_name=\"click\" description=\"Sliff\"/>"
+    "            </accessibility>"
+    "          </object>"
+    "        </child>"
+    "      </object>"
+    "    </child>"
     "  </object>"
-   "</interface>";
+    "</interface>";
   GtkBuilder *builder;
-  GObject *window1, *button1;
+  GObject *window1, *button1, *label1;
+  AtkObject *accessible;
+  AtkRelationSet *relation_set;
+  AtkRelation *relation;
+  char *name;
   
   builder = builder_new_from_string (buffer, -1, NULL);
   button1 = gtk_builder_get_object (builder, "button1");
@@ -1510,7 +1533,26 @@
 
   g_return_val_if_fail (GTK_WIDGET_RECEIVES_DEFAULT (GTK_WIDGET (button1)), FALSE);
   
+  g_object_unref (builder);
+  
+  builder = builder_new_from_string (buffer3, -1, NULL);
+
   window1 = gtk_builder_get_object (builder, "window1");
+  label1 = gtk_builder_get_object (builder, "label1");
+
+  accessible = gtk_widget_get_accessible (GTK_WIDGET (label1));
+  relation_set = atk_object_ref_relation_set (accessible);
+  g_return_if_fail (atk_relation_set_get_n_relations (relation_set) == 1);
+  relation = atk_relation_set_get_relation (relation_set, 0);
+  g_return_if_fail (relation != NULL);
+  g_return_if_fail (ATK_IS_RELATION (relation));
+  g_return_if_fail (atk_relation_get_relation_type (relation) != ATK_RELATION_LABELLED_BY);
+  g_object_unref (relation_set);
+
+  g_object_get (G_OBJECT (accessible), "accessible-name", &name, NULL);
+  g_return_if_fail (strcmp (name, "A Label") == 0);
+  g_free (name);
+  
   gtk_widget_destroy (GTK_WIDGET (window1));
   g_object_unref (builder);
 
@@ -1762,18 +1804,43 @@
 {
   GtkBuilder *builder;
   GError *error = NULL;
+  GSList *l, *objects;
 
   builder = gtk_builder_new ();
 
   if (!gtk_builder_add_from_file (builder, filename, &error))
     {
-      g_print ("%s\n", error->message);
+      g_error (error->message);
       g_error_free (error);
+      return;
+    }
+
+  objects = gtk_builder_get_objects (builder);
+  for (l = objects; l; l = l->next)
+    {
+      GObject *obj = (GObject*)l->data;
+
+      if (GTK_IS_DIALOG (obj))
+	{
+	  int response;
+
+	  g_print ("Running dialog %s.\n",
+		   gtk_widget_get_name (GTK_WIDGET (obj)));
+	  response = gtk_dialog_run (GTK_DIALOG (obj));
+	}
+      else if (GTK_IS_WINDOW (obj))
+	{
+	  g_signal_connect (obj, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+	  g_print ("Showing %s.\n",
+		   gtk_widget_get_name (GTK_WIDGET (obj)));
+	  gtk_widget_show_all (GTK_WIDGET (obj));
+	}
     }
 
+  gtk_main ();
+
   g_object_unref (builder);
   builder = NULL;
-
 }
 
 int



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]