summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordmazzoni <dmazzoni@chromium.org>2015-03-12 14:59:43 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-12 22:00:20 +0000
commitf65bad877350b5f7857d29e4b1b0d4d3f5c7cb6d (patch)
treea25aef584d3719fdfdb5e324f3085dcfee656c64
parent29ecdf6ce41028f5af46a3717ccb88e6e50d1b73 (diff)
downloadchromium_src-f65bad877350b5f7857d29e4b1b0d4d3f5c7cb6d.zip
chromium_src-f65bad877350b5f7857d29e4b1b0d4d3f5c7cb6d.tar.gz
chromium_src-f65bad877350b5f7857d29e4b1b0d4d3f5c7cb6d.tar.bz2
Resurrect Aura Linux accessibility.
This is based in part on the ATK code we had as part of the Linux GTK port that went away, but now rewritten on top of AXPlatformNode. This patch successfully exposes an accessibility tree for Views and exposes top-level windows and the the role and name of each View. You can test it using accerciser. This is just to get the infrastructure in place - we need to implement more of the interface for it to be useful for accessibility tools. BUG=463671 Review URL: https://codereview.chromium.org/975113002 Cr-Commit-Position: refs/heads/master@{#320383}
-rw-r--r--build/config/linux/BUILD.gn19
-rw-r--r--build/config/linux/pkg-config.py13
-rw-r--r--build/linux/system.gyp24
-rw-r--r--chrome/browser/ui/views/chrome_views_delegate.cc5
-rw-r--r--chrome/browser/ui/views/chrome_views_delegate.h1
-rw-r--r--ui/accessibility/BUILD.gn17
-rw-r--r--ui/accessibility/accessibility.gyp25
-rw-r--r--ui/accessibility/platform/atk_util_auralinux.cc161
-rw-r--r--ui/accessibility/platform/atk_util_auralinux.h30
-rw-r--r--ui/accessibility/platform/ax_platform_node.cc2
-rw-r--r--ui/accessibility/platform/ax_platform_node_auralinux.cc277
-rw-r--r--ui/accessibility/platform/ax_platform_node_auralinux.h51
-rw-r--r--ui/accessibility/platform/ax_platform_node_base.h4
-rw-r--r--ui/gfx/native_widget_types.h11
-rw-r--r--ui/views/BUILD.gn1
-rw-r--r--ui/views/accessibility/native_view_accessibility.cc5
-rw-r--r--ui/views/accessibility/native_view_accessibility_auralinux.cc164
-rw-r--r--ui/views/accessibility/native_view_accessibility_auralinux.h27
-rw-r--r--ui/views/views.gyp3
-rw-r--r--ui/views/views_delegate.cc6
-rw-r--r--ui/views/views_delegate.h3
21 files changed, 845 insertions, 4 deletions
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 202fd73..3d65937 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -35,6 +35,25 @@ config("sdk") {
}
}
+pkg_config("atk") {
+ packages = [ "atk" ]
+ atk_lib_dir = exec_script(pkg_config_script,
+ [
+ "--libdir",
+ "atk",
+ ],
+ "string")
+ defines = [ "ATK_LIB_DIR=\"$atk_lib_dir\"" ]
+}
+
+# gn orders flags on a target before flags from configs. The default config
+# adds -Wall, and these flags have to be after -Wall -- so they need to come
+# from a config and can't be on the target directly.
+config("atk_warnings") {
+ # glib uses the pre-c++11 typedef-as-static_assert hack.
+ cflags = [ "-Wno-unused-local-typedef" ]
+}
+
config("fontconfig") {
libs = [ "fontconfig" ]
}
diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py
index a4f4703..fadcc0b 100644
--- a/build/config/linux/pkg-config.py
+++ b/build/config/linux/pkg-config.py
@@ -112,6 +112,7 @@ parser.add_option('-s', action='store', dest='sysroot', type='string')
parser.add_option('-a', action='store', dest='arch', type='string')
parser.add_option('--atleast-version', action='store',
dest='atleast_version', type='string')
+parser.add_option('--libdir', action='store_true', dest='libdir')
(options, args) = parser.parse_args()
# Make a list of regular expressions to strip out.
@@ -138,6 +139,18 @@ if options.atleast_version:
print "false"
sys.exit(0)
+if options.libdir:
+ try:
+ libdir = subprocess.check_output([options.pkg_config,
+ "--variable=libdir"] +
+ args,
+ env=os.environ)
+ except:
+ print "Error from pkg-config."
+ sys.exit(1)
+ sys.stdout.write(libdir.strip())
+ sys.exit(0)
+
try:
flag_string = subprocess.check_output(
[ options.pkg_config, "--cflags", "--libs-only-l", "--libs-only-L" ] +
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index a71a5c5..ed7f942 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -91,6 +91,30 @@
# added back to Chrome OS and Ozone. Don't try to use GTK on Chrome OS and Ozone.
'targets': [
{
+ 'target_name': 'atk',
+ 'type': 'none',
+ 'conditions': [
+ ['_toolset=="target"', {
+ 'direct_dependent_settings': {
+ 'cflags': [
+ '<!@(<(pkg-config) --cflags atk)',
+ ],
+ 'defines': [
+ 'ATK_LIB_DIR="<!@(<(pkg-config) --variable=libdir atk)"',
+ ],
+ },
+ 'link_settings': {
+ 'ldflags': [
+ '<!@(<(pkg-config) --libs-only-L --libs-only-other atk)',
+ ],
+ 'libraries': [
+ '<!@(<(pkg-config) --libs-only-l atk)',
+ ],
+ },
+ }],
+ ],
+ },
+ {
'target_name': 'gdk',
'type': 'none',
'conditions': [
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc
index 82c9190a..daba64b 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser_window_state.h"
+#include "chrome/common/chrome_version_info.h"
#include "content/public/browser/context_factory.h"
#include "grit/chrome_unscaled_resources.h"
#include "ui/base/resource/resource_bundle.h"
@@ -383,6 +384,10 @@ ui::ContextFactory* ChromeViewsDelegate::GetContextFactory() {
return content::GetContextFactory();
}
+std::string ChromeViewsDelegate::GetApplicationName() {
+ return chrome::VersionInfo().Name();
+}
+
#if defined(OS_WIN)
int ChromeViewsDelegate::GetAppbarAutohideEdges(HMONITOR monitor,
const base::Closure& callback) {
diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h
index 3846d9e..d4d197f 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.h
+++ b/chrome/browser/ui/views/chrome_views_delegate.h
@@ -48,6 +48,7 @@ class ChromeViewsDelegate : public views::ViewsDelegate {
bool WindowManagerProvidesTitleBar(bool maximized) override;
#endif
ui::ContextFactory* GetContextFactory() override;
+ std::string GetApplicationName() override;
#if defined(OS_WIN)
virtual int GetAppbarAutohideEdges(HMONITOR monitor,
const base::Closure& callback) override;
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index d168b5e..7ac325e 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/ui.gni")
import("//build/json_schema_api.gni")
import("//testing/test.gni")
@@ -47,6 +48,22 @@ component("accessibility") {
if (is_win) {
public_deps += [ "//third_party/iaccessible2" ]
}
+
+ if (use_aura && !is_chromeos && is_linux) {
+ sources += [
+ "platform/atk_util_auralinux.cc",
+ "platform/atk_util_auralinux.h",
+ "platform/ax_platform_node_auralinux.cc",
+ "platform/ax_platform_node_auralinux.h",
+ ]
+
+ configs += [
+ "//build/config/linux:atk",
+ "//build/config/linux:atk_warnings",
+ "//build/config/linux:gconf",
+ "//build/config/linux:glib",
+ ]
+ }
}
source_set("test_support") {
diff --git a/ui/accessibility/accessibility.gyp b/ui/accessibility/accessibility.gyp
index 88613e6..40146c5 100644
--- a/ui/accessibility/accessibility.gyp
+++ b/ui/accessibility/accessibility.gyp
@@ -43,8 +43,12 @@
'ax_tree_update.h',
'ax_view_state.cc',
'ax_view_state.h',
+ 'platform/atk_util_auralinux.cc',
+ 'platform/atk_util_auralinux.h',
'platform/ax_platform_node.cc',
'platform/ax_platform_node.h',
+ 'platform/ax_platform_node_auralinux.cc',
+ 'platform/ax_platform_node_auralinux.h',
'platform/ax_platform_node_base.cc',
'platform/ax_platform_node_base.h',
'platform/ax_platform_node_delegate.h',
@@ -59,6 +63,27 @@
'../../third_party/iaccessible2/iaccessible2.gyp:iaccessible2'
],
}],
+ ['OS=="linux" and chromeos==0', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:atk',
+ '../../build/linux/system.gyp:gconf',
+ '../../build/linux/system.gyp:glib',
+ ],
+ 'variables': {
+ 'clang_warning_flags': [
+ # glib uses the pre-c++11 typedef-as-static_assert hack.
+ '-Wno-unused-local-typedefs',
+ ],
+ },
+ }],
+ ['OS!="linux" or chromeos==1', {
+ 'sources!': [
+ 'platform/ax_platform_node_auralinux.cc',
+ 'platform/ax_platform_node_auralinux.h',
+ 'platform/atk_util_auralinux.cc',
+ 'platform/atk_util_auralinux.h',
+ ],
+ }],
],
},
{
diff --git a/ui/accessibility/platform/atk_util_auralinux.cc b/ui/accessibility/platform/atk_util_auralinux.cc
new file mode 100644
index 0000000..a15df08
--- /dev/null
+++ b/ui/accessibility/platform/atk_util_auralinux.cc
@@ -0,0 +1,161 @@
+// 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 <atk/atk.h>
+#include <gconf/gconf-client.h>
+#include <glib-2.0/gmodule.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "ui/accessibility/platform/atk_util_auralinux.h"
+#include "ui/accessibility/platform/ax_platform_node_auralinux.h"
+
+namespace {
+
+const char kGnomeAccessibilityEnabledKey[] =
+ "/desktop/gnome/interface/accessibility";
+
+bool ShouldEnableAccessibility() {
+ GConfClient* client = gconf_client_get_default();
+ if (!client) {
+ LOG(ERROR) << "gconf_client_get_default failed";
+ return false;
+ }
+
+ GError* error = nullptr;
+ gboolean value = gconf_client_get_bool(client,
+ kGnomeAccessibilityEnabledKey,
+ &error);
+ if (error) {
+ VLOG(1) << "gconf_client_get_bool failed";
+ g_error_free(error);
+ g_object_unref(client);
+ return false;
+ }
+
+ g_object_unref(client);
+ return value;
+}
+
+} // namespace
+
+G_BEGIN_DECLS
+
+//
+// atk_util_auralinux AtkObject definition and implementation.
+//
+
+#define ATK_UTIL_AURALINUX_TYPE (atk_util_auralinux_get_type())
+#define ATK_UTIL_AURALINUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ ATK_UTIL_AURALINUX_TYPE, \
+ AtkUtilAuraLinux))
+#define ATK_UTIL_AURALINUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ ATK_UTIL_AURALINUX_TYPE, \
+ AtkUtilAuraLinuxClass))
+#define IS_ATK_UTIL_AURALINUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), ATK_UTIL_AURALINUX_TYPE))
+#define IS_ATK_UTIL_AURALINUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), ATK_UTIL_AURALINUX_TYPE))
+#define ATK_UTIL_AURALINUX_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ ATK_UTIL_AURALINUX_TYPE, \
+ AtkUtilAuraLinuxClass))
+
+typedef struct _AtkUtilAuraLinux AtkUtilAuraLinux;
+typedef struct _AtkUtilAuraLinuxClass AtkUtilAuraLinuxClass;
+
+struct _AtkUtilAuraLinux
+{
+ AtkUtil parent;
+};
+
+struct _AtkUtilAuraLinuxClass
+{
+ AtkUtilClass parent_class;
+};
+
+GType atk_util_auralinux_get_type();
+
+G_DEFINE_TYPE(AtkUtilAuraLinux, atk_util_auralinux, ATK_TYPE_UTIL);
+
+static void atk_util_auralinux_init(AtkUtilAuraLinux *ax_util) {
+}
+
+static AtkObject* atk_util_auralinux_get_root() {
+ ui::AXPlatformNode* application = ui::AXPlatformNodeAuraLinux::application();
+ if (application) {
+ return application->GetNativeViewAccessible();
+ }
+ return nullptr;
+}
+
+static G_CONST_RETURN gchar* atk_util_auralinux_get_toolkit_name(void) {
+ return "Chromium";
+}
+
+static G_CONST_RETURN gchar* atk_util_auralinux_get_toolkit_version(void) {
+ return "1.0";
+}
+
+static void atk_util_auralinux_class_init(AtkUtilAuraLinuxClass *klass) {
+ AtkUtilClass *atk_class;
+ gpointer data;
+
+ data = g_type_class_peek(ATK_TYPE_UTIL);
+ atk_class = ATK_UTIL_CLASS(data);
+
+ atk_class->get_root = atk_util_auralinux_get_root;
+ atk_class->get_toolkit_name = atk_util_auralinux_get_toolkit_name;
+ atk_class->get_toolkit_version = atk_util_auralinux_get_toolkit_version;
+}
+
+G_END_DECLS
+
+//
+// AtkUtilAuraLinuxClass implementation.
+//
+
+namespace ui {
+
+// static
+AtkUtilAuraLinux* AtkUtilAuraLinux::GetInstance() {
+ return Singleton<AtkUtilAuraLinux>::get();
+}
+
+AtkUtilAuraLinux::AtkUtilAuraLinux() {
+ // Register our util class.
+ g_type_class_unref(g_type_class_ref(ATK_UTIL_AURALINUX_TYPE));
+
+ if (!ShouldEnableAccessibility()) {
+ VLOG(1) << "Will not enable ATK accessibility support.";
+ return;
+ }
+
+ VLOG(1) << "Enabling ATK accessibility support.";
+
+ // Try to load libatk-bridge.so.
+ base::FilePath atk_bridge_path(ATK_LIB_DIR);
+ atk_bridge_path = atk_bridge_path.Append("gtk-2.0/modules/libatk-bridge.so");
+ GModule* bridge = g_module_open(atk_bridge_path.value().c_str(),
+ static_cast<GModuleFlags>(0));
+ if (!bridge) {
+ VLOG(1) << "Unable to open module " << atk_bridge_path.value();
+ return;
+ }
+
+ // Try to call gnome_accessibility_module_init from libatk-bridge.so.
+ void (*gnome_accessibility_module_init)();
+ if (g_module_symbol(bridge, "gnome_accessibility_module_init",
+ (gpointer *)&gnome_accessibility_module_init)) {
+ (*gnome_accessibility_module_init)();
+ }
+}
+
+AtkUtilAuraLinux::~AtkUtilAuraLinux() {
+}
+
+} // namespace ui
diff --git a/ui/accessibility/platform/atk_util_auralinux.h b/ui/accessibility/platform/atk_util_auralinux.h
new file mode 100644
index 0000000..349c41a
--- /dev/null
+++ b/ui/accessibility/platform/atk_util_auralinux.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_
+#define UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_
+
+#include "base/memory/singleton.h"
+#include "ui/accessibility/ax_export.h"
+
+namespace ui {
+
+// This singleton class initializes ATK (accessibility toolkit) and
+// registers an implementation of the AtkUtil class, a global class that
+// every accessible application needs to register once.
+class AtkUtilAuraLinux {
+ public:
+ // Get the single instance of this class.
+ static AtkUtilAuraLinux* GetInstance();
+
+ AtkUtilAuraLinux();
+ virtual ~AtkUtilAuraLinux();
+
+ private:
+ friend struct DefaultSingletonTraits<AtkUtilAuraLinux>;
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_UTIL_AURALINUX_H_
diff --git a/ui/accessibility/platform/ax_platform_node.cc b/ui/accessibility/platform/ax_platform_node.cc
index 363b3ee..ec268a0 100644
--- a/ui/accessibility/platform/ax_platform_node.cc
+++ b/ui/accessibility/platform/ax_platform_node.cc
@@ -9,7 +9,7 @@
namespace ui {
-#if !defined(OS_MACOSX) && !defined(OS_WIN)
+#if !defined(OS_MACOSX) && !defined(OS_WIN) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
// static
AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
return nullptr;
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
new file mode 100644
index 0000000..7841fa0
--- /dev/null
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -0,0 +1,277 @@
+// 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/accessibility/platform/ax_platform_node_auralinux.h"
+
+#include "base/command_line.h"
+#include "base/strings/sys_string_conversions.h"
+#include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/atk_util_auralinux.h"
+#include "ui/accessibility/platform/ax_platform_node_delegate.h"
+
+//
+// ax_platform_node_auralinux AtkObject definition and implementation.
+//
+
+G_BEGIN_DECLS
+
+#define AX_PLATFORM_NODE_AURALINUX_TYPE (ax_platform_node_auralinux_get_type())
+#define AX_PLATFORM_NODE_AURALINUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST( \
+ (obj), AX_PLATFORM_NODE_AURALINUX_TYPE, AXPlatformNodeAuraLinuxObject))
+#define AX_PLATFORM_NODE_AURALINUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST( \
+ (klass), AX_PLATFORM_NODE_AURALINUX_TYPE, AXPlatformNodeAuraLinuxClass))
+#define IS_AX_PLATFORM_NODE_AURALINUX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), AX_PLATFORM_NODE_AURALINUX_TYPE))
+#define IS_AX_PLATFORM_NODE_AURALINUX_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), AX_PLATFORM_NODE_AURALINUX_TYPE))
+#define AX_PLATFORM_NODE_AURALINUX_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS( \
+ (obj), AX_PLATFORM_NODE_AURALINUX_TYPE, AXPlatformNodeAuraLinuxClass))
+
+typedef struct _AXPlatformNodeAuraLinuxObject AXPlatformNodeAuraLinuxObject;
+typedef struct _AXPlatformNodeAuraLinuxClass AXPlatformNodeAuraLinuxClass;
+
+struct _AXPlatformNodeAuraLinuxObject {
+ AtkObject parent;
+ ui::AXPlatformNodeAuraLinux* m_object;
+};
+
+struct _AXPlatformNodeAuraLinuxClass {
+ AtkObjectClass parent_class;
+};
+
+GType ax_platform_node_auralinux_get_type();
+
+static ui::AXPlatformNodeAuraLinux* ToAXPlatformNodeAuraLinux(
+ AXPlatformNodeAuraLinuxObject* atk_object) {
+ if (!atk_object)
+ return nullptr;
+
+ return atk_object->m_object;
+}
+
+static ui::AXPlatformNodeAuraLinux* ToAXPlatformNodeAuraLinux(
+ AtkObject* atk_object) {
+ if (!atk_object)
+ return nullptr;
+
+ if (IS_AX_PLATFORM_NODE_AURALINUX(atk_object))
+ return ToAXPlatformNodeAuraLinux(AX_PLATFORM_NODE_AURALINUX(atk_object));
+
+ return nullptr;
+}
+
+static const gchar* ax_platform_node_auralinux_get_name(AtkObject* atk_object) {
+ ui::AXPlatformNodeAuraLinux* obj = ToAXPlatformNodeAuraLinux(atk_object);
+ if (!obj)
+ return nullptr;
+
+ return obj->GetStringAttribute(ui::AX_ATTR_NAME).c_str();
+}
+
+static const gchar* ax_platform_node_auralinux_get_description(
+ AtkObject* atk_object) {
+ ui::AXPlatformNodeAuraLinux* obj = ToAXPlatformNodeAuraLinux(atk_object);
+ if (!obj)
+ return nullptr;
+
+ return obj->GetStringAttribute(
+ ui::AX_ATTR_DESCRIPTION).c_str();
+}
+
+static AtkObject* ax_platform_node_auralinux_get_parent(AtkObject* atk_object) {
+ ui::AXPlatformNodeAuraLinux* obj = ToAXPlatformNodeAuraLinux(atk_object);
+ if (!obj)
+ return nullptr;
+
+ return obj->GetParent();
+}
+
+static gint ax_platform_node_auralinux_get_n_children(AtkObject* atk_object) {
+ ui::AXPlatformNodeAuraLinux* obj = ToAXPlatformNodeAuraLinux(atk_object);
+ if (!obj)
+ return 0;
+
+ return obj->GetChildCount();
+}
+
+static AtkObject* ax_platform_node_auralinux_ref_child(
+ AtkObject* atk_object, gint index) {
+ ui::AXPlatformNodeAuraLinux* obj = ToAXPlatformNodeAuraLinux(atk_object);
+ if (!obj)
+ return nullptr;
+
+ AtkObject* result = obj->ChildAtIndex(index);
+ if (result)
+ g_object_ref(result);
+ return result;
+}
+
+static AtkRole ax_platform_node_auralinux_get_role(AtkObject* atk_object) {
+ ui::AXPlatformNodeAuraLinux* obj = ToAXPlatformNodeAuraLinux(atk_object);
+ if (!obj)
+ return ATK_ROLE_INVALID;
+ return obj->GetAtkRole();
+}
+
+//
+// The rest of the AXPlatformNodeAuraLinux code, not specific to one
+// of the Atk* interfaces.
+//
+
+static gpointer ax_platform_node_auralinux_parent_class = nullptr;
+
+static void ax_platform_node_auralinux_init(AtkObject* atk_object,
+ gpointer data) {
+ if (ATK_OBJECT_CLASS(ax_platform_node_auralinux_parent_class)->initialize) {
+ ATK_OBJECT_CLASS(ax_platform_node_auralinux_parent_class)->initialize(
+ atk_object, data);
+ }
+
+ AX_PLATFORM_NODE_AURALINUX(atk_object)->m_object =
+ reinterpret_cast<ui::AXPlatformNodeAuraLinux*>(data);
+}
+
+static void ax_platform_node_auralinux_finalize(GObject* atk_object) {
+ G_OBJECT_CLASS(ax_platform_node_auralinux_parent_class)->finalize(atk_object);
+}
+
+static void ax_platform_node_auralinux_class_init(AtkObjectClass* klass) {
+ GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
+ ax_platform_node_auralinux_parent_class = g_type_class_peek_parent(klass);
+
+ gobject_class->finalize = ax_platform_node_auralinux_finalize;
+ klass->initialize = ax_platform_node_auralinux_init;
+ klass->get_name = ax_platform_node_auralinux_get_name;
+ klass->get_description = ax_platform_node_auralinux_get_description;
+ klass->get_parent = ax_platform_node_auralinux_get_parent;
+ klass->get_n_children = ax_platform_node_auralinux_get_n_children;
+ klass->ref_child = ax_platform_node_auralinux_ref_child;
+ klass->get_role = ax_platform_node_auralinux_get_role;
+}
+
+GType ax_platform_node_auralinux_get_type() {
+ static volatile gsize type_volatile = 0;
+
+ if (g_once_init_enter(&type_volatile)) {
+ static const GTypeInfo tinfo = {
+ sizeof(AXPlatformNodeAuraLinuxClass),
+ (GBaseInitFunc) 0,
+ (GBaseFinalizeFunc) 0,
+ (GClassInitFunc) ax_platform_node_auralinux_class_init,
+ (GClassFinalizeFunc) 0,
+ 0, /* class data */
+ sizeof(AXPlatformNodeAuraLinuxObject), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) 0,
+ 0 /* value table */
+ };
+
+ GType type = g_type_register_static(
+ ATK_TYPE_OBJECT, "AXPlatformNodeAuraLinux", &tinfo, GTypeFlags(0));
+ g_once_init_leave(&type_volatile, type);
+ }
+
+ return type_volatile;
+}
+
+AXPlatformNodeAuraLinuxObject* ax_platform_node_auralinux_new(
+ ui::AXPlatformNodeAuraLinux* obj) {
+ #if !GLIB_CHECK_VERSION(2, 36, 0)
+ static bool first_time = true;
+ if (first_time) {
+ g_type_init();
+ first_time = false;
+ }
+ #endif
+
+ GType type = AX_PLATFORM_NODE_AURALINUX_TYPE;
+ AtkObject* atk_object = static_cast<AtkObject*>(g_object_new(type, 0));
+ atk_object_initialize(atk_object, obj);
+ return AX_PLATFORM_NODE_AURALINUX(atk_object);
+}
+
+void ax_platform_node_auralinux_detach(
+ AXPlatformNodeAuraLinuxObject* atk_object) {
+ atk_object->m_object = nullptr;
+}
+
+G_END_DECLS
+
+//
+// AXPlatformNodeAuraLinux implementation.
+//
+
+namespace ui {
+
+// static
+AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
+ AXPlatformNodeAuraLinux* node = new AXPlatformNodeAuraLinux();
+ node->Init(delegate);
+ return node;
+}
+
+// static
+AXPlatformNode* AXPlatformNodeAuraLinux::application_ = nullptr;
+
+// static
+void AXPlatformNodeAuraLinux::SetApplication(AXPlatformNode* application) {
+ application_ = application;
+ AtkUtilAuraLinux::GetInstance();
+}
+
+AtkRole AXPlatformNodeAuraLinux::GetAtkRole() {
+ switch (GetData().role) {
+ case ui::AX_ROLE_APPLICATION:
+ return ATK_ROLE_APPLICATION;
+ case ui::AX_ROLE_BUTTON:
+ return ATK_ROLE_PUSH_BUTTON;
+ case ui::AX_ROLE_CHECK_BOX:
+ return ATK_ROLE_CHECK_BOX;
+ case ui::AX_ROLE_COMBO_BOX:
+ return ATK_ROLE_COMBO_BOX;
+ case ui::AX_ROLE_STATIC_TEXT:
+ return ATK_ROLE_TEXT;
+ case ui::AX_ROLE_TEXT_FIELD:
+ return ATK_ROLE_ENTRY;
+ case ui::AX_ROLE_WINDOW:
+ return ATK_ROLE_WINDOW;
+ default:
+ return ATK_ROLE_UNKNOWN;
+ }
+}
+
+AXPlatformNodeAuraLinux::AXPlatformNodeAuraLinux()
+ : atk_object_(nullptr) {
+}
+
+AXPlatformNodeAuraLinux::~AXPlatformNodeAuraLinux() {
+ g_object_unref(atk_object_);
+}
+
+void AXPlatformNodeAuraLinux::Init(AXPlatformNodeDelegate* delegate) {
+ // Initialize ATK.
+ AXPlatformNodeBase::Init(delegate);
+ atk_object_ = ATK_OBJECT(ax_platform_node_auralinux_new(this));
+}
+
+void AXPlatformNodeAuraLinux::Destroy() {
+ delegate_ = nullptr;
+ delete this;
+}
+
+gfx::NativeViewAccessible AXPlatformNodeAuraLinux::GetNativeViewAccessible() {
+ return atk_object_;
+}
+
+void AXPlatformNodeAuraLinux::NotifyAccessibilityEvent(ui::AXEvent event_type) {
+}
+
+int AXPlatformNodeAuraLinux::GetIndexInParent() {
+ return 0;
+}
+
+} // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h
new file mode 100644
index 0000000..eea1427
--- /dev/null
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_
+#define UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_
+
+#include <atk/atk.h>
+
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/platform/ax_platform_node_base.h"
+
+namespace ui {
+
+// Implements accessibility on Aura Linux using ATK.
+class AXPlatformNodeAuraLinux : public AXPlatformNodeBase {
+ public:
+ AXPlatformNodeAuraLinux();
+
+ // Set or get the root-level Application object that's the parent of all
+ // top-level windows.
+ AX_EXPORT static void SetApplication(AXPlatformNode* application);
+ static AXPlatformNode* application() { return application_; }
+
+ AtkRole GetAtkRole();
+
+ // AXPlatformNode overrides.
+ void Destroy() override;
+ gfx::NativeViewAccessible GetNativeViewAccessible() override;
+ void NotifyAccessibilityEvent(ui::AXEvent event_type) override;
+
+ // AXPlatformNodeBase overrides.
+ void Init(AXPlatformNodeDelegate* delegate) override;
+ int GetIndexInParent() override;
+
+ private:
+ ~AXPlatformNodeAuraLinux() override;
+
+ // We own a reference to this ref-counted object.
+ AtkObject* atk_object_;
+
+ // The root-level Application object that's the parent of all
+ // top-level windows.
+ static AXPlatformNode* application_;
+
+ DISALLOW_COPY_AND_ASSIGN(AXPlatformNodeAuraLinux);
+};
+
+} // namespace ui
+
+#endif // UI_ACCESSIBILITY_AX_PLATFORM_NODE_AURALINUX_H_
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 7555ec0..324b239 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -61,6 +61,8 @@ class AXPlatformNodeBase : public AXPlatformNode {
base::string16 GetString16Attribute(
ui::AXStringAttribute attribute) const;
+ AXPlatformNodeDelegate* delegate_; // Weak. Owns this.
+
protected:
AXPlatformNodeBase();
~AXPlatformNodeBase() override;
@@ -70,7 +72,7 @@ class AXPlatformNodeBase : public AXPlatformNode {
static AXPlatformNodeBase* FromNativeViewAccessible(
gfx::NativeViewAccessible accessible);
- AXPlatformNodeDelegate* delegate_; // Weak. Owns this.
+
private:
DISALLOW_COPY_AND_ASSIGN(AXPlatformNodeBase);
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index 8cf8a5f..1a8256b 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -106,6 +106,13 @@ class ViewAndroid;
#endif
class SkBitmap;
+#if defined(USE_X11) && !defined(OS_CHROMEOS)
+extern "C" {
+struct _AtkObject;
+typedef struct _AtkObject AtkObject;
+}
+#endif
+
namespace gfx {
#if defined(USE_AURA)
@@ -164,8 +171,12 @@ typedef cairo_t* NativeDrawingContext;
#else
typedef void* NativeDrawingContext;
#endif // defined(USE_CAIRO)
+#if defined(USE_X11) && !defined(OS_CHROMEOS)
+typedef AtkObject* NativeViewAccessible;
+#else
typedef void* NativeViewAccessible;
#endif
+#endif
// A constant value to indicate that gfx::NativeCursor refers to no cursor.
#if defined(USE_AURA)
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 922ce0c..528d4bb 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -109,6 +109,7 @@ component("views") {
}
if (is_linux) {
sources += gypi_values.views_desktop_aura_linux_sources
+ configs += [ "//build/config/linux:atk" ]
}
}
}
diff --git a/ui/views/accessibility/native_view_accessibility.cc b/ui/views/accessibility/native_view_accessibility.cc
index aeb2c70..a11f773 100644
--- a/ui/views/accessibility/native_view_accessibility.cc
+++ b/ui/views/accessibility/native_view_accessibility.cc
@@ -13,7 +13,7 @@
namespace views {
-#if !defined(OS_WIN)
+#if !defined(OS_WIN) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS))
// static
NativeViewAccessibility* NativeViewAccessibility::Create(View* view) {
return new NativeViewAccessibility(view);
@@ -23,7 +23,8 @@ NativeViewAccessibility* NativeViewAccessibility::Create(View* view) {
NativeViewAccessibility::NativeViewAccessibility(View* view)
: view_(view),
parent_widget_(nullptr),
- ax_node_(ui::AXPlatformNode::Create(this)) {
+ ax_node_(nullptr) {
+ ax_node_ = ui::AXPlatformNode::Create(this);
}
NativeViewAccessibility::~NativeViewAccessibility() {
diff --git a/ui/views/accessibility/native_view_accessibility_auralinux.cc b/ui/views/accessibility/native_view_accessibility_auralinux.cc
new file mode 100644
index 0000000..afee535
--- /dev/null
+++ b/ui/views/accessibility/native_view_accessibility_auralinux.cc
@@ -0,0 +1,164 @@
+// 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 <vector>
+
+#include "base/memory/singleton.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 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 (std::find(widgets_.begin(), widgets_.end(), widget) != widgets_.end())
+ return;
+
+ widgets_.push_back(widget);
+ widget->AddObserver(this);
+ }
+
+ gfx::NativeViewAccessible GetNativeViewAccessible() {
+ return platform_node_->GetNativeViewAccessible();
+ }
+
+ //
+ // WidgetObserver overrides.
+ //
+
+ void OnWidgetDestroying(Widget* widget) override {
+ auto iter = std::find(widgets_.begin(), widgets_.end(), widget);
+ if (iter != widgets_.end())
+ widgets_.erase(iter);
+ }
+
+ //
+ // ui::AXPlatformNodeDelegate overrides.
+ //
+
+ const ui::AXNodeData& GetData() override {
+ return data_;
+ }
+
+ 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;
+ }
+
+ void DoDefaultAction() override {
+ }
+
+ bool SetStringValue(const base::string16& new_value) override {
+ return false;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<AuraLinuxApplication>;
+
+ AuraLinuxApplication()
+ : platform_node_(ui::AXPlatformNode::Create(this)) {
+ data_.role = ui::AX_ROLE_APPLICATION;
+ if (ViewsDelegate::views_delegate) {
+ data_.AddStringAttribute(
+ ui::AX_ATTR_NAME,
+ ViewsDelegate::views_delegate->GetApplicationName());
+ }
+ ui::AXPlatformNodeAuraLinux::SetApplication(platform_node_);
+ }
+
+ ~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
+NativeViewAccessibility* NativeViewAccessibility::Create(View* view) {
+ AuraLinuxApplication::GetInstance()->RegisterWidget(view->GetWidget());
+ return new NativeViewAccessibilityAuraLinux(view);
+}
+
+NativeViewAccessibilityAuraLinux::NativeViewAccessibilityAuraLinux(View* view)
+ : NativeViewAccessibility(view) {
+}
+
+NativeViewAccessibilityAuraLinux::~NativeViewAccessibilityAuraLinux() {
+}
+
+gfx::NativeViewAccessible NativeViewAccessibilityAuraLinux::GetParent() {
+ gfx::NativeViewAccessible parent = NativeViewAccessibility::GetParent();
+ if (!parent)
+ parent = AuraLinuxApplication::GetInstance()->GetNativeViewAccessible();
+ return parent;
+}
+
+} // namespace views
diff --git a/ui/views/accessibility/native_view_accessibility_auralinux.h b/ui/views/accessibility/native_view_accessibility_auralinux.h
new file mode 100644
index 0000000..f817dc7
--- /dev/null
+++ b/ui/views/accessibility/native_view_accessibility_auralinux.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef UI_VIEWS_ACCESSIBILITY_NATIVE_VIEW_ACCESSIBILITY_AURALINUX_H_
+#define UI_VIEWS_ACCESSIBILITY_NATIVE_VIEW_ACCESSIBILITY_AURALINUX_H_
+
+#include "ui/views/accessibility/native_view_accessibility.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+class NativeViewAccessibilityAuraLinux : public NativeViewAccessibility {
+ public:
+ NativeViewAccessibilityAuraLinux(View* view);
+ ~NativeViewAccessibilityAuraLinux() override;
+
+ // NativeViewAccessibility.
+ gfx::NativeViewAccessible GetParent() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeViewAccessibilityAuraLinux);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_ACCESSIBILITY_NATIVE_VIEW_ACCESSIBILITY_AURALINUX_H_
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 0b92a2c..0ad2fae 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -419,6 +419,8 @@
'widget/desktop_aura/desktop_window_tree_host.h',
],
'views_desktop_aura_linux_sources': [
+ 'accessibility/native_view_accessibility_auralinux.cc',
+ 'accessibility/native_view_accessibility_auralinux.h',
'widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc',
'widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h',
],
@@ -635,6 +637,7 @@
}],
['OS=="linux" and chromeos==0', {
'dependencies': [
+ '../../build/linux/system.gyp:atk',
'../shell_dialogs/shell_dialogs.gyp:shell_dialogs',
],
'sources!': [
diff --git a/ui/views/views_delegate.cc b/ui/views/views_delegate.cc
index de9ccbb..4c1ae4f 100644
--- a/ui/views/views_delegate.cc
+++ b/ui/views/views_delegate.cc
@@ -4,6 +4,7 @@
#include "ui/views/views_delegate.h"
+#include "base/command_line.h"
#include "ui/views/views_touch_selection_controller_factory.h"
namespace views {
@@ -85,6 +86,11 @@ ui::ContextFactory* ViewsDelegate::GetContextFactory() {
return NULL;
}
+std::string ViewsDelegate::GetApplicationName() {
+ base::FilePath program = base::CommandLine::ForCurrentProcess()->GetProgram();
+ return program.BaseName().AsUTF8Unsafe();
+}
+
#if defined(OS_WIN)
int ViewsDelegate::GetAppbarAutohideEdges(HMONITOR monitor,
const base::Closure& callback) {
diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h
index 6cc5a6b..ea14e78 100644
--- a/ui/views/views_delegate.h
+++ b/ui/views/views_delegate.h
@@ -135,6 +135,9 @@ class VIEWS_EXPORT ViewsDelegate {
// Returns the context factory for new windows.
virtual ui::ContextFactory* GetContextFactory();
+ // Returns the user-visible name of the application.
+ virtual std::string GetApplicationName();
+
#if defined(OS_WIN)
// Starts a query for the appbar autohide edges of the specified monitor and
// returns the current value. If the query finds the edges have changed from