| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/views/accessibility/native_view_accessibility_auralinux.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <vector> |
| |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/singleton.h" |
| #include "base/stl_util.h" |
| #include "ui/accessibility/ax_action_data.h" |
| #include "ui/accessibility/ax_enums.h" |
| #include "ui/accessibility/ax_node_data.h" |
| #include "ui/accessibility/platform/ax_platform_node_auralinux.h" |
| #include "ui/accessibility/platform/ax_platform_node_delegate.h" |
| #include "ui/gfx/native_widget_types.h" |
| #include "ui/views/views_delegate.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/widget/widget_observer.h" |
| |
| namespace views { |
| |
| namespace { |
| |
| // ATK requires that we have a single root "application" object that's the |
| // owner of all other windows. This is a simple class that implements the |
| // AXPlatformNodeDelegate interface so we can create such an application |
| // object. Every time we create an accessibility object for a View, we add its |
| // top-level widget to a vector so we can return the list of all top-level |
| // windows as children of this application object. |
| class AuraLinuxApplication |
| : public ui::AXPlatformNodeDelegate, |
| public WidgetObserver { |
| public: |
| // Get the single instance of this class. |
| static AuraLinuxApplication* GetInstance() { |
| return base::Singleton<AuraLinuxApplication>::get(); |
| } |
| |
| // Called every time we create a new accessibility on a View. |
| // Add the top-level widget to our registry so that we can enumerate all |
| // top-level widgets. |
| void RegisterWidget(Widget* widget) { |
| if (!widget) |
| return; |
| |
| widget = widget->GetTopLevelWidget(); |
| if (base::ContainsValue(widgets_, widget)) |
| return; |
| |
| widgets_.push_back(widget); |
| widget->AddObserver(this); |
| } |
| |
| gfx::NativeViewAccessible GetNativeViewAccessible() { |
| return platform_node_->GetNativeViewAccessible(); |
| } |
| |
| // WidgetObserver: |
| |
| void OnWidgetDestroying(Widget* widget) override { |
| auto iter = std::find(widgets_.begin(), widgets_.end(), widget); |
| if (iter != widgets_.end()) |
| widgets_.erase(iter); |
| } |
| |
| // ui::AXPlatformNodeDelegate: |
| |
| const ui::AXNodeData& GetData() const override { return data_; } |
| |
| gfx::NativeWindow GetTopLevelWidget() override { return nullptr; } |
| |
| gfx::NativeViewAccessible GetParent() override { |
| return nullptr; |
| } |
| |
| int GetChildCount() override { |
| return static_cast<int>(widgets_.size()); |
| } |
| |
| gfx::NativeViewAccessible ChildAtIndex(int index) override { |
| if (index < 0 || index >= GetChildCount()) |
| return nullptr; |
| |
| Widget* widget = widgets_[index]; |
| CHECK(widget); |
| return widget->GetRootView()->GetNativeViewAccessible(); |
| } |
| |
| gfx::Vector2d GetGlobalCoordinateOffset() override { |
| return gfx::Vector2d(); |
| } |
| |
| gfx::NativeViewAccessible HitTestSync(int x, int y) override { |
| return nullptr; |
| } |
| |
| gfx::NativeViewAccessible GetFocus() override { |
| return nullptr; |
| } |
| |
| gfx::AcceleratedWidget GetTargetForNativeAccessibilityEvent() override { |
| return gfx::kNullAcceleratedWidget; |
| } |
| |
| bool AccessibilityPerformAction(const ui::AXActionData& data) override { |
| return false; |
| } |
| |
| void DoDefaultAction() override {} |
| |
| private: |
| friend struct base::DefaultSingletonTraits<AuraLinuxApplication>; |
| |
| AuraLinuxApplication() |
| : platform_node_(ui::AXPlatformNode::Create(this)) { |
| data_.role = ui::AX_ROLE_APPLICATION; |
| if (ViewsDelegate::GetInstance()) { |
| data_.AddStringAttribute( |
| ui::AX_ATTR_NAME, |
| ViewsDelegate::GetInstance()->GetApplicationName()); |
| } |
| ui::AXPlatformNodeAuraLinux::SetApplication(platform_node_); |
| if (ViewsDelegate::GetInstance()) { |
| // This should be on the a blocking pool thread so that we can open |
| // libatk-bridge.so without blocking this thread. |
| scoped_refptr<base::TaskRunner> init_task_runner = |
| ViewsDelegate::GetInstance()->GetBlockingPoolTaskRunner(); |
| if (init_task_runner) |
| ui::AXPlatformNodeAuraLinux::StaticInitialize(init_task_runner); |
| } |
| } |
| |
| ~AuraLinuxApplication() override { |
| platform_node_->Destroy(); |
| platform_node_ = nullptr; |
| } |
| |
| ui::AXPlatformNode* platform_node_; |
| ui::AXNodeData data_; |
| std::vector<Widget*> widgets_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AuraLinuxApplication); |
| }; |
| |
| } // namespace |
| |
| // static |
| std::unique_ptr<NativeViewAccessibility> NativeViewAccessibility::Create( |
| View* view) { |
| AuraLinuxApplication::GetInstance()->RegisterWidget(view->GetWidget()); |
| return base::MakeUnique<NativeViewAccessibilityAuraLinux>(view); |
| } |
| |
| NativeViewAccessibilityAuraLinux::NativeViewAccessibilityAuraLinux(View* view) |
| : NativeViewAccessibilityBase(view) {} |
| |
| NativeViewAccessibilityAuraLinux::~NativeViewAccessibilityAuraLinux() { |
| } |
| |
| gfx::NativeViewAccessible NativeViewAccessibilityAuraLinux::GetParent() { |
| gfx::NativeViewAccessible parent = NativeViewAccessibilityBase::GetParent(); |
| if (!parent) |
| parent = AuraLinuxApplication::GetInstance()->GetNativeViewAccessible(); |
| return parent; |
| } |
| |
| } // namespace views |