Merge lp:~mardy/autopilot-gtk/atk into lp:autopilot-gtk

Proposed by Alberto Mardegan
Status: Merged
Approved by: Allan LeSage
Approved revision: 35
Merged at revision: 33
Proposed branch: lp:~mardy/autopilot-gtk/atk
Merge into: lp:autopilot-gtk
Diff against target: 144 lines (+65/-1)
3 files modified
lib/GtkNode.cpp (+56/-1)
lib/GtkNode.h (+4/-0)
lib/GtkRootNode.cpp (+5/-0)
To merge this branch: bzr merge lp:~mardy/autopilot-gtk/atk
Reviewer Review Type Date Requested Status
Allan LeSage (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+155909@code.launchpad.net

Commit message

Export the ATK objects hierarchy as well

AtkObject interfaces are meant for accessibility, and expose more information
which can be useful for automated testing. For instance, it is possible to
enumerate and introspect all the cells in a GtkTreeView.

This patch exposes the ATK objects hierarchies as children of the root node;
the existing GtkWidget hierarchy is left untouched, and can still be used.

Description of the change

Export the ATK objects hierarchy as well

AtkObject interfaces are meant for accessibility, and expose more information
which can be useful for automated testing. For instance, it is possible to
enumerate and introspect all the cells in a GtkTreeView.

This patch exposes the ATK objects hierarchies as children of the root node;
the existing GtkWidget hierarchy is left untouched, and can still be used.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~mardy/autopilot-gtk/atk updated
34. By Alberto Mardegan

Skip accessible-table-* properties

These properties are not implemented (ATK bug?).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Allan LeSage (allanlesage) wrote :

Alberto, would you offer a sample script or two for my testing convenience?

To this point I'm attempting just to 'autopilot launch gedit' and to inspect the properties using autopilot vis; I'm finding that the globalRects are giving absurd numbers--is this not true for you?

Lastly I wonder if you'd object to just making a function out of the EXPORT_STATE macro--I'm trying to hang on to a C++-like standard for the project, at least for the moment :) .

lp:~mardy/autopilot-gtk/atk updated
35. By Alberto Mardegan

Remove usage of preprocessor macro

Revision history for this message
Alberto Mardegan (mardy) wrote :

> Alberto, would you offer a sample script or two for my testing convenience?
>
> To this point I'm attempting just to 'autopilot launch gedit' and to inspect
> the properties using autopilot vis; I'm finding that the globalRects are
> giving absurd numbers--is this not true for you?

Yes. Unfortunately unless the items are visible on screen, those values are bogus.
But they are correct, when the item is actually on screen.

> Lastly I wonder if you'd object to just making a function out of the
> EXPORT_STATE macro--I'm trying to hang on to a C++-like standard for the
> project, at least for the moment :) .

I removed the macro now. It's not worth to make it a function, as it would take 4 parameters so in practice not make the code any easier to read. :-)

Revision history for this message
Alberto Mardegan (mardy) wrote :
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Allan LeSage (allanlesage) wrote :

I was able to write a small test to experiment with ATK-bindings; thanks Alberto for your changes.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/GtkNode.cpp'
2--- lib/GtkNode.cpp 2013-01-31 21:10:24 +0000
3+++ lib/GtkNode.cpp 2013-04-16 05:36:24 +0000
4@@ -22,12 +22,17 @@
5
6 #include <string>
7 #include "GtkNode.h"
8-#include "Variant.h"
9
10 const std::string GtkNode::AP_ID_NAME = "id";
11
12 GtkNode::GtkNode(GObject* obj)
13 : object_(obj) {
14+ if (object_ != NULL) g_object_ref(object_);
15+}
16+
17+GtkNode::~GtkNode()
18+{
19+ g_clear_object(&object_);
20 }
21
22 GVariant* GtkNode::Introspect() const
23@@ -41,6 +46,10 @@
24 variant::BuilderWrapper builder_wrapper(&builder);
25 for (uint i = 0; i < length; ++i) {
26 GParamSpec* param_spec = properties[i];
27+ // ATK's accessible-table-* properties generate "invalid property id" warnings
28+ std::string prefix("accessible-table-");
29+ if (std::string(g_param_spec_get_name(param_spec)).compare(0, prefix.length(), prefix) == 0)
30+ continue;
31 // see Launchpad bug #1108155: GtkTreePath mis-casts while copying, actuates here in "root" property
32 if (std::string(g_type_name(param_spec->value_type)) != "GtkTreePath") {
33 // some properties are only writeable; some toxic nodes change their names (?)
34@@ -75,6 +84,8 @@
35 GVariant *rect_gvariant = ComposeRectVariant(rect.x, rect.y, rect.width, rect.height);
36 builder_wrapper.add("globalRect", rect_gvariant);
37 }
38+ } else if (ATK_IS_COMPONENT(object_)) {
39+ AddAtkComponentProperties(builder_wrapper, ATK_COMPONENT(object_));
40 }
41 return g_variant_builder_end(&builder);
42 }
43@@ -91,6 +102,43 @@
44 return g_variant_builder_end(&builder);
45 }
46
47+void GtkNode::AddAtkComponentProperties(variant::BuilderWrapper &builder_wrapper,
48+ AtkComponent *atk_component) const
49+{
50+ AtkStateSet *states = atk_object_ref_state_set(ATK_OBJECT(atk_component));
51+
52+ /* Expose a few states which might be especially interesting for autopilot */
53+ bool visible = atk_state_set_contains_state(states, ATK_STATE_VISIBLE);
54+ builder_wrapper.add("visible", visible);
55+ if (visible) {
56+ gint x, y, width, height;
57+ atk_component_get_extents(atk_component, &x, &y, &width, &height,
58+ ATK_XY_SCREEN);
59+ GVariant *rect_gvariant = ComposeRectVariant(x, y, width, height);
60+ builder_wrapper.add("globalRect", rect_gvariant);
61+ }
62+
63+ builder_wrapper.add("active",
64+ bool(atk_state_set_contains_state(states, ATK_STATE_ACTIVE)));
65+ builder_wrapper.add("checked",
66+ bool(atk_state_set_contains_state(states, ATK_STATE_CHECKED)));
67+ builder_wrapper.add("editable",
68+ bool(atk_state_set_contains_state(states, ATK_STATE_EDITABLE)));
69+ builder_wrapper.add("enabled",
70+ bool(atk_state_set_contains_state(states, ATK_STATE_ENABLED)));
71+ builder_wrapper.add("focused",
72+ bool(atk_state_set_contains_state(states, ATK_STATE_FOCUSED)));
73+ builder_wrapper.add("pressed",
74+ bool(atk_state_set_contains_state(states, ATK_STATE_PRESSED)));
75+ builder_wrapper.add("selected",
76+ bool(atk_state_set_contains_state(states, ATK_STATE_SELECTED)));
77+ builder_wrapper.add("sensitive",
78+ bool(atk_state_set_contains_state(states, ATK_STATE_SENSITIVE)));
79+ builder_wrapper.add("showing",
80+ bool(atk_state_set_contains_state(states, ATK_STATE_SHOWING)));
81+ g_object_unref(G_OBJECT(states));
82+}
83+
84 intptr_t GtkNode::GetObjectId() const {
85 return reinterpret_cast<intptr_t>(object_);
86 }
87@@ -154,6 +202,13 @@
88 children.push_back(std::make_shared<GtkNode>(G_OBJECT(elem->data)));
89 }
90 g_list_free(gtk_children);
91+ } else if (ATK_IS_OBJECT(object_)) {
92+ AtkObject *atk_object = ATK_OBJECT(object_);
93+ int n_children = atk_object_get_n_accessible_children(atk_object);
94+ for (int i = 0; i < n_children; i++) {
95+ AtkObject *child = atk_object_ref_accessible_child(atk_object, i);
96+ children.push_back(std::make_shared<GtkNode>(G_OBJECT(child)));
97+ }
98 }
99
100 return children;
101
102=== modified file 'lib/GtkNode.h'
103--- lib/GtkNode.h 2013-01-30 20:09:43 +0000
104+++ lib/GtkNode.h 2013-04-16 05:36:24 +0000
105@@ -25,12 +25,14 @@
106 #include <xpathselect/node.h>
107 #include <xpathselect/xpathselect.h>
108 #include <string>
109+#include "Variant.h"
110
111 class GtkNode: public xpathselect::Node {
112 public:
113 typedef std::shared_ptr<GtkNode> Ptr;
114
115 GtkNode(GObject* object);
116+ virtual ~GtkNode();
117
118 virtual GVariant* Introspect() const;
119
120@@ -48,6 +50,8 @@
121 virtual intptr_t GetObjectId() const;
122 virtual void GetGlobalRect(GdkRectangle* rect) const;
123 virtual GVariant* ComposeRectVariant(gint x, gint y, gint height, gint width) const;
124+ void AddAtkComponentProperties(variant::BuilderWrapper &builder_wrapper,
125+ AtkComponent *atk_component) const;
126 };
127
128 #endif // GTKNODE_H
129
130=== modified file 'lib/GtkRootNode.cpp'
131--- lib/GtkRootNode.cpp 2013-01-31 21:10:24 +0000
132+++ lib/GtkRootNode.cpp 2013-04-16 05:36:24 +0000
133@@ -69,6 +69,11 @@
134 for (elem = toplevels_list; elem; elem = elem->next) {
135 GObject *node = reinterpret_cast<GObject*>(elem->data);
136 children.push_back(std::make_shared<GtkNode>(node));
137+
138+ // if the AtkObjects are available, expose the Atk hierarchy as well
139+ AtkObject *atk_object = gtk_widget_get_accessible(GTK_WIDGET(node));
140+ if (atk_object != NULL)
141+ children.push_back(std::make_shared<GtkNode>(G_OBJECT(atk_object)));
142 }
143 g_list_free(toplevels_list);
144 return children;

Subscribers

People subscribed via source and target branches