Merge lp:~apinheiro/unity/a11y-improve-window-event-emission into lp:unity

Proposed by Alejandro Piñeiro
Status: Merged
Approved by: Alex Launi
Approved revision: no longer in the source branch.
Merged at revision: 1810
Proposed branch: lp:~apinheiro/unity/a11y-improve-window-event-emission
Merge into: lp:unity
Prerequisite: lp:~apinheiro/unity/a11y-quicklist
Diff against target: 458 lines (+111/-163)
8 files modified
plugins/unityshell/src/nux-base-window-accessible.cpp (+34/-125)
plugins/unityshell/src/nux-base-window-accessible.h (+2/-5)
plugins/unityshell/src/nux-view-accessible.cpp (+0/-13)
plugins/unityshell/src/unity-launcher-icon-accessible.cpp (+0/-1)
plugins/unityshell/src/unity-quicklist-accessible.cpp (+0/-3)
plugins/unityshell/src/unity-quicklist-menu-accessible.cpp (+1/-1)
plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp (+3/-0)
plugins/unityshell/src/unity-root-accessible.cpp (+71/-15)
To merge this branch: bzr merge lp:~apinheiro/unity/a11y-improve-window-event-emission
Reviewer Review Type Date Requested Status
Alex Launi (community) Approve
Neil J. Patel Pending
Review via email: mp+79290@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Alejandro Piñeiro (apinheiro) wrote :

BTW, this branch is already being tested by the users, as it is included on this branch:

https://launchpad.net/~apinheiro/+archive/unity-extra-a11y

I already received some positive feedback from ubuntu-accessibility mailing list

Revision history for this message
Alex Launi (alexlauni) wrote :

API, could you please also include some tests for these merges? We're focusing on increaing our test code coverage and the a11y layer is an important part to be tested

review: Needs Fixing
Revision history for this message
Alejandro Piñeiro (apinheiro) wrote :

> API, could you please also include some tests for these merges? We're focusing
> on increaing our test code coverage and the a11y layer is an important part to
> be tested

Yes it is true that a lot of new features were included without no new tests. Anyway, as most of those branches are already really big, and in order to keep things clean, could it possible to add tests on a different merge proposal?. In that way I could start to work on adding tests for a more global a11y support.

For example this branch is basically a improvement of previous branch, so I feel that include also tests there would be like mixing different things.

And after all, it would be good to check if it would be possible to move the a11y tests to the normal a11y directory. When I created those tests, I couldn't add them to the tests directory because there I couldn't included some Unity headers (I don't remember the details, I think that are detailed on a mail or on other merge proposal).

Revision history for this message
Alex Launi (alexlauni) wrote :

Ok, sounds fair. Could you please propose some test branches as soon as possible?

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

No proposals found for merge of lp:~apinheiro/unity/a11y-quicklist into lp:unity.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/unityshell/src/nux-base-window-accessible.cpp'
2--- plugins/unityshell/src/nux-base-window-accessible.cpp 2011-11-07 22:02:27 +0000
3+++ plugins/unityshell/src/nux-base-window-accessible.cpp 2011-11-07 22:02:27 +0000
4@@ -46,15 +46,6 @@
5 #include <Nux/Area.h>
6 #include <Nux/Layout.h>
7
8-enum
9-{
10- ACTIVATE,
11- DEACTIVATE,
12- LAST_SIGNAL
13-};
14-
15-static guint signals [LAST_SIGNAL] = { 0, };
16-
17 /* GObject */
18 static void nux_base_window_accessible_class_init(NuxBaseWindowAccessibleClass* klass);
19 static void nux_base_window_accessible_init(NuxBaseWindowAccessible* base_window_accessible);
20@@ -65,20 +56,19 @@
21 static AtkObject* nux_base_window_accessible_get_parent(AtkObject* obj);
22 static AtkStateSet* nux_base_window_accessible_ref_state_set(AtkObject* obj);
23
24-/* private */
25-static void on_change_keyboard_receiver_cb(AtkObject* accessible,
26- gboolean focus_in);
27-
28-G_DEFINE_TYPE(NuxBaseWindowAccessible, nux_base_window_accessible, NUX_TYPE_VIEW_ACCESSIBLE)
29+/* AtkWindow.h */
30+static void atk_window_interface_init(AtkWindowIface* iface);
31+
32+
33+G_DEFINE_TYPE_WITH_CODE(NuxBaseWindowAccessible, nux_base_window_accessible,
34+ NUX_TYPE_VIEW_ACCESSIBLE,
35+ G_IMPLEMENT_INTERFACE(ATK_TYPE_WINDOW,
36+ atk_window_interface_init))
37
38 struct _NuxBaseWindowAccessiblePrivate
39 {
40 /* Cached values (used to avoid extra notifications) */
41 gboolean active;
42-
43- gboolean key_focused;
44- gboolean child_key_focused;
45- /* so active = key_focused || child_key_focused */
46 };
47
48 #define NUX_BASE_WINDOW_ACCESSIBLE_GET_PRIVATE(obj) \
49@@ -97,45 +87,6 @@
50 atk_class->ref_state_set = nux_base_window_accessible_ref_state_set;
51
52 g_type_class_add_private(gobject_class, sizeof(NuxBaseWindowAccessiblePrivate));
53-
54- /**
55- * BaseWindow::activate:
56- * @nux_object: the object which received the signal
57- *
58- * The ::activate signal is emitted when the window receives the key
59- * focus from the underlying window system.
60- *
61- * Toolkit implementation note: it is used when anyone adds a global
62- * event listener to "window:activate"
63- */
64- signals [ACTIVATE] =
65- g_signal_new("activate",
66- G_TYPE_FROM_CLASS(klass),
67- G_SIGNAL_RUN_LAST,
68- 0, /* default signal handler */
69- NULL, NULL,
70- g_cclosure_marshal_VOID__VOID,
71- G_TYPE_NONE, 0);
72-
73- /**
74- * BaseWindow::deactivate:
75- * @nux_object: the object which received the signal
76- *
77- * The ::deactivate signal is emitted when the window loses key
78- * focus from the underlying window system.
79- *
80- * Toolkit implementation note: it is used when anyone adds a global
81- * event listener to "window:deactivate"
82- */
83- signals [DEACTIVATE] =
84- g_signal_new("deactivate",
85- G_TYPE_FROM_CLASS(klass),
86- G_SIGNAL_RUN_LAST,
87- 0, /* default signal handler */
88- NULL, NULL,
89- g_cclosure_marshal_VOID__VOID,
90- G_TYPE_NONE, 0);
91-
92 }
93
94 static void
95@@ -166,21 +117,9 @@
96 nux_base_window_accessible_initialize(AtkObject* accessible,
97 gpointer data)
98 {
99- nux::Object* nux_object = NULL;
100- nux::BaseWindow* bwindow = NULL;
101-
102 ATK_OBJECT_CLASS(nux_base_window_accessible_parent_class)->initialize(accessible, data);
103
104- accessible->role = ATK_ROLE_WINDOW;
105-
106- nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible));
107- bwindow = dynamic_cast<nux::BaseWindow*>(nux_object);
108-
109- /* This gives us if the window has the underlying key input */
110- bwindow->begin_key_focus.connect(sigc::bind(sigc::ptr_fun(on_change_keyboard_receiver_cb),
111- accessible, TRUE));
112- bwindow->end_key_focus.connect(sigc::bind(sigc::ptr_fun(on_change_keyboard_receiver_cb),
113- accessible, FALSE));
114+ atk_object_set_role(accessible, ATK_ROLE_WINDOW);
115 }
116
117 static AtkObject*
118@@ -219,76 +158,46 @@
119 return state_set;
120 }
121
122-/* private */
123+/* AtkWindow */
124 static void
125-check_active(NuxBaseWindowAccessible* self)
126-{
127- gint signal_id;
128+atk_window_interface_init(AtkWindowIface* iface)
129+{
130+ /* AtkWindow just define signals at this moment */
131+}
132+
133+/* public */
134+/*
135+ * Checks if we are the active window.
136+ */
137+void
138+nux_base_window_accessible_check_active(NuxBaseWindowAccessible* self,
139+ nux::BaseWindow* active_window)
140+{
141+ const gchar* signal_name;
142 gboolean is_active;
143 nux::Object* nux_object = NULL;
144+ nux::BaseWindow* bwindow = NULL;
145+
146+ g_return_if_fail(NUX_IS_BASE_WINDOW_ACCESSIBLE(self));
147
148 nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self));
149- if (nux_object == NULL) /* defunct */
150+ bwindow = dynamic_cast<nux::BaseWindow*>(nux_object);
151+ if (bwindow == NULL) /* defunct */
152 return;
153
154- /* FIXME: this method is not infalible, as we lose some
155- window->deactivate, specifically on the Dash, so this could be
156- improved. As we check the active window using UBus messages we
157- could use that information, but would make complex the
158- quicklist.
159-
160- Anyway, the relevant message is the activate window, it is ok if
161- we lose some deactivate methods for the moment */
162- is_active = (self->priv->key_focused || self->priv->child_key_focused);
163+ is_active = (bwindow == active_window);
164
165 if (self->priv->active != is_active)
166 {
167 self->priv->active = is_active;
168
169 if (is_active)
170- signal_id = ACTIVATE;
171+ signal_name = "activate";
172 else
173- signal_id = DEACTIVATE;
174+ signal_name = "deactivate";
175
176 atk_object_notify_state_change(ATK_OBJECT(self),
177 ATK_STATE_ACTIVE, is_active);
178- g_signal_emit(self, signals [signal_id], 0);
179- }
180-}
181-
182-static void
183-on_change_keyboard_receiver_cb(AtkObject* object,
184- gboolean focus_in)
185-{
186- NuxBaseWindowAccessible* self = NULL;
187-
188- /* On the base window, we suppose that the window is active if it
189- has the key focus (see nux::InputArea) */
190- self = NUX_BASE_WINDOW_ACCESSIBLE(object);
191-
192- if (self->priv->key_focused != focus_in)
193- {
194- self->priv->key_focused = focus_in;
195- }
196-}
197-
198-/* public */
199-void
200-nux_base_window_set_child_key_focused(NuxBaseWindowAccessible* self,
201- gboolean value)
202-{
203- g_return_if_fail(NUX_IS_BASE_WINDOW_ACCESSIBLE(self));
204-
205- if (self->priv->child_key_focused != value)
206- {
207- self->priv->child_key_focused = value;
208- }
209-}
210-
211-void
212-nux_base_window_accessible_check_active(NuxBaseWindowAccessible* self)
213-{
214- g_return_if_fail(NUX_IS_BASE_WINDOW_ACCESSIBLE(self));
215-
216- check_active(self);
217+ g_signal_emit_by_name(self, signal_name, 0);
218+ }
219 }
220
221=== modified file 'plugins/unityshell/src/nux-base-window-accessible.h'
222--- plugins/unityshell/src/nux-base-window-accessible.h 2011-11-07 22:02:27 +0000
223+++ plugins/unityshell/src/nux-base-window-accessible.h 2011-11-07 22:02:27 +0000
224@@ -54,11 +54,8 @@
225
226 GType nux_base_window_accessible_get_type(void);
227 AtkObject* nux_base_window_accessible_new(nux::Object* object);
228-
229-void nux_base_window_set_child_key_focused(NuxBaseWindowAccessible* self,
230- gboolean value);
231-
232-void nux_base_window_accessible_check_active(NuxBaseWindowAccessible* self);
233+void nux_base_window_accessible_check_active(NuxBaseWindowAccessible* self,
234+ nux::BaseWindow* active_window);
235
236
237 G_END_DECLS
238
239=== modified file 'plugins/unityshell/src/nux-view-accessible.cpp'
240--- plugins/unityshell/src/nux-view-accessible.cpp 2011-11-07 22:02:27 +0000
241+++ plugins/unityshell/src/nux-view-accessible.cpp 2011-11-07 22:02:27 +0000
242@@ -260,21 +260,8 @@
243
244 if (self->priv->key_focused != focus_in)
245 {
246- AtkObject* parent_window = NULL;
247-
248 self->priv->key_focused = focus_in;
249
250- /* this child has the key focus, so we report the top level
251- * window about it. FIXME: that only works if only one object of
252- * the children hierarchy can have the key focus, that is the
253- * case here */
254-
255- parent_window =
256- nux_area_accessible_get_parent_window(NUX_AREA_ACCESSIBLE(self));
257-
258- nux_base_window_set_child_key_focused(NUX_BASE_WINDOW_ACCESSIBLE(parent_window),
259- focus_in);
260-
261 /* we always led the focus notification to
262 _check_pending_notification, in order to allow the proper
263 window_activate -> focus_change order */
264
265=== modified file 'plugins/unityshell/src/unity-launcher-icon-accessible.cpp'
266--- plugins/unityshell/src/unity-launcher-icon-accessible.cpp 2011-10-06 04:18:36 +0000
267+++ plugins/unityshell/src/unity-launcher-icon-accessible.cpp 2011-11-07 22:02:27 +0000
268@@ -326,7 +326,6 @@
269 atk_object_notify_state_change(ATK_OBJECT(self),
270 ATK_STATE_ACTIVE,
271 found);
272-
273 g_signal_emit_by_name(self, "focus-event", self->priv->selected, &return_val);
274 atk_focus_tracker_notify(ATK_OBJECT(self));
275 }
276
277=== modified file 'plugins/unityshell/src/unity-quicklist-accessible.cpp'
278--- plugins/unityshell/src/unity-quicklist-accessible.cpp 2011-11-07 22:02:27 +0000
279+++ plugins/unityshell/src/unity-quicklist-accessible.cpp 2011-11-07 22:02:27 +0000
280@@ -132,9 +132,6 @@
281
282 if (quicklist == NULL) /* status defunct */
283 return;
284-
285- atk_object_set_name(accessible, "Quicklist");
286-
287 }
288
289 static gint
290
291=== modified file 'plugins/unityshell/src/unity-quicklist-menu-accessible.cpp'
292--- plugins/unityshell/src/unity-quicklist-menu-accessible.cpp 2011-11-07 22:02:27 +0000
293+++ plugins/unityshell/src/unity-quicklist-menu-accessible.cpp 2011-11-07 22:02:27 +0000
294@@ -174,7 +174,7 @@
295 return;
296
297 atk_object_set_role(accessible, ATK_ROLE_MENU);
298- atk_object_set_name(accessible, "QuicklistMenu");
299+ atk_object_set_name(accessible, _("Quicklist"));
300
301 self->priv->on_selection_change_connection =
302 quicklist->selection_change.connect(sigc::bind(sigc::ptr_fun(on_selection_change_cb), self));
303
304=== modified file 'plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp'
305--- plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp 2011-11-07 22:02:27 +0000
306+++ plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp 2011-11-07 22:02:27 +0000
307@@ -279,6 +279,9 @@
308
309 self->priv->selected = found;
310 atk_object_notify_state_change(ATK_OBJECT(self),
311+ ATK_STATE_FOCUSED,
312+ found);
313+ atk_object_notify_state_change(ATK_OBJECT(self),
314 ATK_STATE_SELECTED,
315 found);
316 atk_object_notify_state_change(ATK_OBJECT(self),
317
318=== modified file 'plugins/unityshell/src/unity-root-accessible.cpp'
319--- plugins/unityshell/src/unity-root-accessible.cpp 2011-11-07 22:02:27 +0000
320+++ plugins/unityshell/src/unity-root-accessible.cpp 2011-11-07 22:02:27 +0000
321@@ -21,7 +21,8 @@
322 * @short_description: Root object for the UNITY accessible support
323 *
324 * #UnityRootAccessible is the root object of the accessibility
325- * tree-like hierarchy, exposing the application level.
326+ * tree-like hierarchy, exposing the application level. You can see it
327+ * as the one exposing UnityScreen information to the a11y framework
328 *
329 */
330
331@@ -63,6 +64,8 @@
332 /* we save on window_list the accessible object for the windows
333 registered */
334 GSList* window_list;
335+ nux::BaseWindow* active_window;
336+ nux::BaseWindow* launcher_window;
337 };
338
339 static void
340@@ -88,6 +91,8 @@
341 root->priv = UNITY_ROOT_ACCESSIBLE_GET_PRIVATE(root);
342
343 root->priv->window_list = NULL;
344+ root->priv->active_window = NULL;
345+ root->priv->launcher_window = NULL;
346 }
347
348 AtkObject*
349@@ -231,8 +236,7 @@
350 for (iter = self->priv->window_list; iter != NULL; iter = g_slist_next(iter))
351 {
352 window = NUX_BASE_WINDOW_ACCESSIBLE(iter->data);
353-
354- nux_base_window_accessible_check_active(window);
355+ nux_base_window_accessible_check_active(window, self->priv->active_window);
356 }
357 }
358
359@@ -303,19 +307,78 @@
360 }
361
362 static void
363-ubus_change_visibility_cb(GVariant* variant,
364- UnityRootAccessible* self)
365+set_active_window(UnityRootAccessible* self,
366+ nux::BaseWindow* window)
367 {
368+ g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(self));
369+ g_return_if_fail(window != NULL);
370+
371+ self->priv->active_window = window;
372 check_active_window(self);
373 }
374
375-static void
376-wc_change_visibility_window_cb(nux::BaseWindow* window, UnityRootAccessible* self, gboolean visible)
377+nux::BaseWindow*
378+search_for_launcher_window(UnityRootAccessible* self)
379+{
380+ GSList*iter = NULL;
381+ nux::Object* nux_object = NULL;
382+ nux::BaseWindow* bwindow = NULL;
383+ NuxObjectAccessible* accessible = NULL;
384+ gboolean found = FALSE;
385+
386+ for (iter = self->priv->window_list; iter != NULL; iter = g_slist_next(iter))
387+ {
388+ accessible = NUX_OBJECT_ACCESSIBLE(iter->data);
389+
390+ nux_object = nux_object_accessible_get_object(accessible);
391+ bwindow = dynamic_cast<nux::BaseWindow*>(nux_object);
392+
393+ if ((bwindow!= NULL) && (g_strcmp0(bwindow->GetWindowName().GetTCharPtr(), "Launcher") == 0))
394+ {
395+ found = TRUE;
396+ break;
397+ }
398+ }
399+
400+ if (found)
401+ return bwindow;
402+ else
403+ return NULL;
404+}
405+
406+static void
407+ubus_launcher_start_key_nav_cb(GVariant* variant,
408+ UnityRootAccessible* self)
409+{
410+ //launcher window is the same during all the life of Unity
411+ if (self->priv->launcher_window == NULL)
412+ self->priv->launcher_window = search_for_launcher_window(self);
413+
414+ //launcher window became the active window
415+ set_active_window(self, self->priv->launcher_window);
416+}
417+
418+
419+static void
420+wc_change_visibility_window_cb(nux::BaseWindow* window,
421+ UnityRootAccessible* self,
422+ gboolean visible)
423 {
424 if (visible)
425+ {
426 add_window(self, window);
427+ //for the dash and quicklist
428+ set_active_window(self, window);
429+ }
430 else
431+ {
432+ AtkObject* accessible = NULL;
433+
434+ accessible = unity_a11y_get_accessible(window);
435+ nux_base_window_accessible_check_active(NUX_BASE_WINDOW_ACCESSIBLE(accessible),
436+ NULL);
437 remove_window(self, window);
438+ }
439 }
440
441 static void
442@@ -323,15 +386,8 @@
443 {
444 static unity::UBusManager ubus_manager;
445
446- ubus_manager.RegisterInterest(UBUS_PLACE_VIEW_SHOWN,
447- sigc::bind(sigc::ptr_fun(ubus_change_visibility_cb), self));
448- ubus_manager.RegisterInterest(UBUS_PLACE_VIEW_HIDDEN,
449- sigc::bind(sigc::ptr_fun(ubus_change_visibility_cb), self));
450-
451 ubus_manager.RegisterInterest(UBUS_LAUNCHER_START_KEY_NAV,
452- sigc::bind(sigc::ptr_fun(ubus_change_visibility_cb), self));
453- ubus_manager.RegisterInterest(UBUS_LAUNCHER_END_KEY_NAV,
454- sigc::bind(sigc::ptr_fun(ubus_change_visibility_cb), self));
455+ sigc::bind(sigc::ptr_fun(ubus_launcher_start_key_nav_cb), self));
456
457 nux::GetWindowCompositor().sigVisibleViewWindow.
458 connect(sigc::bind(sigc::ptr_fun(wc_change_visibility_window_cb), self, TRUE));