Commit 67b183f2 authored by Martin Robinson's avatar Martin Robinson Committed by Commit Bot

Emit an ATK focus signal after popup menus are finished

Orca expects this signal, so we make sure to fire it when popup menus
are closed. We also send the ax::mojom::Event::kMenuPopupEnd event after
the ax::mojom::Event::kMenuEnd event to make sure that any "focus
override" in the Views code is unset. We do this because we need to
query the currently focused item after the menu is closed.

Bug: 1011864
Change-Id: I0137527c349bb7f3a6ade66fd9ceadba3e0d546e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1855742
Commit-Queue: Martin Robinson <mrobinson@igalia.com>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709034}
parent 28d91524
......@@ -3126,6 +3126,19 @@ void AXPlatformNodeAuraLinux::OnMenuPopupHide() {
}
}
void AXPlatformNodeAuraLinux::ResendFocusSignalsForCurrentlyFocusedNode() {
auto* frame = AtkObjectToAXPlatformNodeAuraLinux(g_active_top_level_frame);
if (!frame)
return;
AtkObject* focused_node = frame->GetDelegate()->GetFocus();
if (!focused_node)
return;
g_signal_emit_by_name(focused_node, "focus-event", true);
atk_object_notify_state_change(focused_node, ATK_STATE_FOCUSED, true);
}
void AXPlatformNodeAuraLinux::OnMenuPopupEnd() {
if (!GetActiveMenus().empty() && g_active_top_level_frame &&
ComputeActiveTopLevelFrame() != g_active_top_level_frame) {
......@@ -3134,6 +3147,7 @@ void AXPlatformNodeAuraLinux::OnMenuPopupEnd() {
TRUE);
}
ResendFocusSignalsForCurrentlyFocusedNode();
GetActiveMenus().clear();
}
......
......@@ -169,6 +169,7 @@ class AX_EXPORT AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
void OnWindowVisibilityChanged();
void OnScrolledToAnchor();
void ResendFocusSignalsForCurrentlyFocusedNode();
bool SupportsSelectionWithAtkSelection();
bool SelectionAndFocusAreTheSame();
......
......@@ -1728,21 +1728,27 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
root.id = 1;
root.role = ax::mojom::Role::kApplication;
root.child_ids.push_back(2);
root.child_ids.push_back(3);
root.child_ids.push_back(4);
AXNodeData window_node_data;
window_node_data.id = 2;
window_node_data.role = ax::mojom::Role::kWindow;
window_node_data.child_ids.push_back(3);
AXNodeData document_node_data;
document_node_data.id = 3;
document_node_data.role = ax::mojom::Role::kRootWebArea;
AXNodeData menu_node_data;
menu_node_data.id = 3;
menu_node_data.id = 4;
menu_node_data.role = ax::mojom::Role::kWindow;
menu_node_data.child_ids.push_back(4);
menu_node_data.child_ids.push_back(5);
AXNodeData menu_item_data;
menu_item_data.id = 4;
menu_item_data.id = 5;
Init(root, window_node_data, menu_node_data, menu_item_data);
Init(root, window_node_data, document_node_data, menu_node_data,
menu_item_data);
AtkObject* root_atk_object(GetRootAtkObject());
EXPECT_TRUE(ATK_IS_OBJECT(root_atk_object));
......@@ -1751,6 +1757,19 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
AXNode* window_node = GetRootNode()->children()[0];
AtkObject* window_atk_node(AtkObjectFromNode(window_node));
AXNode* document_node = window_node->children()[0];
AtkObject* document_atk_node(AtkObjectFromNode(document_node));
EXPECT_EQ(ATK_ROLE_DOCUMENT_WEB, atk_object_get_role(document_atk_node));
int focus_events_on_original_node = 0;
g_signal_connect(
document_atk_node, "focus-event",
G_CALLBACK(+[](AtkObject* atkobject, gint focused, int* focus_events) {
if (focused)
*focus_events += 1;
}),
&focus_events_on_original_node);
atk_component_grab_focus(ATK_COMPONENT(document_atk_node));
ActivationTester toplevel_tester(window_atk_node);
GetPlatformNode(window_node)
->NotifyAccessibilityEvent(ax::mojom::Event::kWindowActivated);
......@@ -1769,6 +1788,7 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
EXPECT_TRUE(tester.saw_activate_);
EXPECT_FALSE(tester.saw_deactivate_);
EXPECT_TRUE(tester.IsActivatedInStateSet());
EXPECT_EQ(focus_events_on_original_node, 0);
}
EXPECT_FALSE(toplevel_tester.saw_activate_);
......@@ -1783,6 +1803,7 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
EXPECT_FALSE(tester.saw_activate_);
EXPECT_TRUE(tester.saw_deactivate_);
EXPECT_FALSE(tester.IsActivatedInStateSet());
EXPECT_EQ(focus_events_on_original_node, 0);
}
{
......@@ -1792,6 +1813,10 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
EXPECT_FALSE(tester.saw_activate_);
EXPECT_FALSE(tester.saw_deactivate_);
EXPECT_FALSE(tester.IsActivatedInStateSet());
// The menu has closed so the original node should have received focus
// again.
EXPECT_EQ(focus_events_on_original_node, 1);
}
// Now that the menu is definitively closed, activation should have returned
......@@ -1799,8 +1824,9 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
EXPECT_TRUE(toplevel_tester.saw_activate_);
EXPECT_FALSE(toplevel_tester.saw_deactivate_);
// No we test opening the menu and closing it without hiding any submenus. The
// toplevel should lose and then regain focus.
// Now we test opening the menu and closing it without hiding any submenus.
// The toplevel should lose and then regain focus.
focus_events_on_original_node = 0;
toplevel_tester.Reset();
GetPlatformNode(menu_node)->NotifyAccessibilityEvent(
......@@ -1810,6 +1836,9 @@ TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkPopupWindowActive) {
EXPECT_TRUE(toplevel_tester.saw_activate_);
EXPECT_TRUE(toplevel_tester.saw_deactivate_);
// The menu has closed so the original node should have received focus again.
EXPECT_EQ(focus_events_on_original_node, 1);
g_object_unref(root_atk_object);
}
......
......@@ -408,9 +408,13 @@ void SubmenuView::Reposition(const gfx::Rect& bounds) {
void SubmenuView::Close() {
if (host_) {
NotifyAccessibilityEvent(ax::mojom::Event::kMenuPopupEnd, true);
// We send the event to the ScrollViewContainer first because the View
// accessibility delegate sets up a focus override when receiving the
// kMenuStart event that we want to be disabled when we send the
// kMenuPopupEnd event in order to access the previously focused node.
GetScrollViewContainer()->NotifyAccessibilityEvent(
ax::mojom::Event::kMenuEnd, true);
NotifyAccessibilityEvent(ax::mojom::Event::kMenuPopupEnd, true);
host_->DestroyMenuHost();
host_ = nullptr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment