Implement accessible support, fixes #454653.
2008-01-25 Johan Dahlin <johan@gnome.org> * 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 improve the test_file function to display toplevels and run dialogs. svn path=/trunk/; revision=19403
This commit is contained in:
committed by
Johan Dahlin
parent
7b8050aff2
commit
fddc9b8561
17
ChangeLog
17
ChangeLog
@ -1,3 +1,20 @@
|
||||
2008-01-25 Johan Dahlin <johan@gnome.org>
|
||||
|
||||
* 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.
|
||||
|
||||
2008-01-25 Richard Hult <richard@imendio.com>
|
||||
|
||||
* gdk/quartz/GdkQuartzView.c: Don't recreate a tracking rect if it
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
2008-01-24 Johan Dahlin <johan@gnome.org>
|
||||
|
||||
* gtk/tmpl/gtkwidget.sgml:
|
||||
Add documentation for <accessible> buildable tag.
|
||||
|
||||
2008-01-14 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* gtk/gtk-docs.sgml:
|
||||
|
||||
@ -37,6 +37,31 @@ modifiers and signal and allows to specify accelerators.
|
||||
</object>
|
||||
]]></programlisting>
|
||||
</example>
|
||||
In addition to accelerators, <structname>GtkWidget</structname> also support a
|
||||
custom <accessible> 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 ##### -->
|
||||
|
||||
@ -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>
|
||||
#
|
||||
@ -124,7 +124,7 @@ def get_accelerator_nodes(node):
|
||||
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:
|
||||
@ -178,7 +178,7 @@ class GtkBuilderConverter(object):
|
||||
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 +207,23 @@ class GtkBuilderConverter(object):
|
||||
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 +262,10 @@ class GtkBuilderConverter(object):
|
||||
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,
|
||||
@ -421,7 +426,7 @@ class GtkBuilderConverter(object):
|
||||
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')
|
||||
@ -514,12 +519,12 @@ class GtkBuilderConverter(object):
|
||||
value, lower, upper, step, page, page_size = data.split(' ')
|
||||
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=dict(value=value,
|
||||
lower=lower,
|
||||
upper=upper,
|
||||
step_increment=step,
|
||||
page_increment=page,
|
||||
page_size=page_size))
|
||||
prop.childNodes[0].data = adj.getAttribute('id')
|
||||
|
||||
def _convert_combobox_items(self, node, prop):
|
||||
@ -581,7 +586,7 @@ class GtkBuilderConverter(object):
|
||||
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 +628,35 @@ class GtkBuilderConverter(object):
|
||||
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:
|
||||
|
||||
@ -60,7 +60,6 @@ gtk_test_init (int *argcp,
|
||||
* FUTURE TODO:
|
||||
* - this function could install a mock object around GtkSettings
|
||||
*/
|
||||
g_setenv ("GTK_MODULES", "", TRUE);
|
||||
g_setenv ("GTK2_RC_FILES", "/dev/null", TRUE);
|
||||
gtk_disable_setlocale();
|
||||
setlocale (LC_ALL, "C");
|
||||
|
||||
316
gtk/gtkwidget.c
316
gtk/gtkwidget.c
@ -251,6 +251,9 @@ static void gtk_widget_buildable_interface_init (GtkBuildableIfa
|
||||
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,
|
||||
@ -8786,17 +8789,20 @@ gtk_widget_ref_accessible (AtkImplementor *implementor)
|
||||
/*
|
||||
* 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;
|
||||
@ -8816,6 +8822,17 @@ gtk_widget_buildable_get_name (GtkBuildable *buildable)
|
||||
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,
|
||||
@ -8832,16 +8849,223 @@ gtk_widget_buildable_set_buildable_property (GtkBuildable *buildable,
|
||||
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;
|
||||
@ -8894,12 +9118,6 @@ static const GMarkupParser accel_group_parser =
|
||||
accel_group_start_element,
|
||||
};
|
||||
|
||||
static const GMarkupParser accessibility_parser =
|
||||
{
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_widget_buildable_custom_tag_start (GtkBuildable *buildable,
|
||||
GtkBuilder *builder,
|
||||
@ -8908,31 +9126,25 @@ gtk_widget_buildable_custom_tag_start (GtkBuildable *buildable,
|
||||
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;
|
||||
@ -8945,17 +9157,18 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
|
||||
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)
|
||||
{
|
||||
@ -8967,15 +9180,56 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1468,14 +1468,37 @@ test_widget (void)
|
||||
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");
|
||||
@ -1493,20 +1516,28 @@ test_widget (void)
|
||||
|
||||
g_assert (GTK_WIDGET_RECEIVES_DEFAULT (GTK_WIDGET (button1)));
|
||||
|
||||
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);
|
||||
|
||||
if (g_test_thorough())
|
||||
{
|
||||
/* this test currently triggers:
|
||||
* "Gtk-WARNING **: <accessibility> is being ignored, see http://bugzilla.gnome.org/show_bug.cgi?id=454653"
|
||||
*/
|
||||
builder = builder_new_from_string (buffer3, -1, NULL);
|
||||
window1 = gtk_builder_get_object (builder, "window1");
|
||||
gtk_widget_destroy (GTK_WIDGET (window1));
|
||||
g_object_unref (builder);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1746,18 +1777,43 @@ test_file (const gchar *filename)
|
||||
{
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user