diff --git a/src/Makefile.am b/src/Makefile.am index 0740f0667..f252e5bc1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -81,6 +81,8 @@ libgnome_shell_la_SOURCES = \ shell-wm-private.h \ gnome-shell-plugin.c \ shell-app.c \ + shell-a11y.h \ + shell-a11y.c \ shell-app-system.c \ shell-app-usage.c \ shell-arrow.c \ diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c index c77cbdae4..96075f41f 100644 --- a/src/gnome-shell-plugin.c +++ b/src/gnome-shell-plugin.c @@ -52,6 +52,7 @@ #include "shell-perf-log.h" #include "shell-wm-private.h" #include "st.h" +#include "shell-a11y.h" static void gnome_shell_plugin_dispose (GObject *object); static void gnome_shell_plugin_finalize (GObject *object); @@ -420,6 +421,8 @@ gnome_shell_plugin_start (MetaPlugin *plugin) bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + shell_a11y_init (); + settings = gtk_settings_get_default (); g_object_connect (settings, "signal::notify::gtk-xft-dpi", diff --git a/src/gnome-shell.in b/src/gnome-shell.in index 8500d98cb..a1610293c 100755 --- a/src/gnome-shell.in +++ b/src/gnome-shell.in @@ -219,12 +219,23 @@ def start_shell(perf_output=None): js_dir = os.path.join('@pkgdatadir@', 'js') # Set up environment + + # About the value of NO_GAIL and NO_AT_BRIDGE: If a11y is enabled, + # gtk_init() will normally load gail and at-bridge. But we don't + # want at-bridge to be loaded until after clutter is initialized + # (which mutter does after initializing gtk) and we don't want + # gail to be loaded at all. So set these flags. shell_a11y_init() + # will clear them so they don't get passed to gnome-shell's + # children. + env = dict(os.environ) env.update({'GNOME_SHELL_JS' : js_dir, 'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', ''), 'XDG_CONFIG_DIRS' : '@sysconfdir@/xdg:' + (os.environ.get('XDG_CONFIG_DIRS') or '/etc/xdg'), 'XDG_DATA_DIRS' : '@datadir@:' + (os.environ.get('XDG_DATA_DIRS') or '/usr/local/share:/usr/share'), - 'GNOME_DISABLE_CRASH_DIALOG' : '1'}) + 'GNOME_DISABLE_CRASH_DIALOG' : '1', + 'NO_GAIL' : '1', + 'NO_AT_BRIDGE' : '1'}) if running_from_source_tree: env.update({'GNOME_SHELL_DATADIR' : data_dir, diff --git a/src/shell-a11y.c b/src/shell-a11y.c new file mode 100644 index 000000000..1715cf649 --- /dev/null +++ b/src/shell-a11y.c @@ -0,0 +1,165 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Igalia, S.L. + * + * Author: Alejandro Piñeiro Iglesias + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include + +#include "shell-a11y.h" + +#define INIT_METHOD "gnome_accessibility_module_init" +#define DESKTOP_SCHEMA "org.gnome.desktop.interface" +#define ACCESSIBILITY_ENABLED_KEY "accessibility" +#define AT_SPI_SCHEMA "org.a11y.atspi" +#define ATK_BRIDGE_LOCATION_KEY "atk-bridge-location" + +static gboolean +should_enable_a11y (void) +{ + GSettings *desktop_settings = NULL; + gboolean value = FALSE; + + desktop_settings = g_settings_new (DESKTOP_SCHEMA); + value = g_settings_get_boolean (desktop_settings, ACCESSIBILITY_ENABLED_KEY); + + g_object_unref (desktop_settings); + + return value; +} + +static char* +get_atk_bridge_path (void) +{ + GSettings *atspi_settings = NULL; + char *value = NULL; + const char * const *schemas = NULL; + gboolean found = FALSE; + int i = 0; + + schemas = g_settings_list_schemas (); + + for (i = 0; schemas [i]; i++) + { + if (!strcmp (schemas[i], AT_SPI_SCHEMA)) + { + found = TRUE; + break; + } + } + + if (!found) + { + g_warning ("Accessibility: %s schema not found. Are you sure that at-spi or" + " at-spi2 is installed on your system?", AT_SPI_SCHEMA); + return NULL; + } + + atspi_settings = g_settings_new (AT_SPI_SCHEMA); + value = g_settings_get_string (atspi_settings, ATK_BRIDGE_LOCATION_KEY); + + g_object_unref (atspi_settings); + + return value; +} + +static gboolean +a11y_invoke_module (const char *module_path) +{ + GModule *handle; + void (*invoke_fn) (void); + + if (!module_path) + { + g_warning ("Accessibility: invalid module path (NULL)"); + + return FALSE; + } + + if (!(handle = g_module_open (module_path, 0))) + { + g_warning ("Accessibility: failed to load module '%s': '%s'", + module_path, g_module_error ()); + + return FALSE; + } + + if (!g_module_symbol (handle, INIT_METHOD, (gpointer *)&invoke_fn)) + { + g_warning ("Accessibility: error library '%s' does not include " + "method '%s' required for accessibility support", + module_path, INIT_METHOD); + g_module_close (handle); + + return FALSE; + } + + invoke_fn (); + + return TRUE; +} + +/* + * It loads the atk-bridge if required. It checks: + * * If the proper gsetting key is set + * * If clutter has already enabled the accessibility + * + * You need to ensure that the atk-bridge was not loaded before this + * call, because in that case the application would be already + * registered on at-spi using the AtkUtil implementation on that + * moment (if any, although without anyone the application would + * crash). Anyway this is the reason of NO_AT_BRIDGE. + * + */ +void +shell_a11y_init (void) +{ + char *bridge_path = NULL; + + g_unsetenv ("NO_AT_BRIDGE"); + g_unsetenv ("NO_GAIL"); + + if (!should_enable_a11y ()) + return; + + if (clutter_get_accessibility_enabled () == FALSE) + { + g_warning ("Accessibility: clutter has no accessibility enabled" + " skipping the atk-bridge load"); + return; + } + + bridge_path = get_atk_bridge_path (); + + if (a11y_invoke_module (bridge_path) == FALSE) + { + g_warning ("Accessibility: error loading the atk-bridge. Although the" + " accessibility on the system is enabled and clutter" + " accessibility is also enabled, accessibility support on" + " GNOME Shell will not work"); + } + + /* NOTE: We avoid to load gail module, as gail-cally interaction is + * not fully supported right now. + */ + + g_free (bridge_path); +} diff --git a/src/shell-a11y.h b/src/shell-a11y.h new file mode 100644 index 000000000..12e77ae41 --- /dev/null +++ b/src/shell-a11y.h @@ -0,0 +1,32 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2010 Igalia, S.L. + * + * Author: Alejandro Piñeiro Iglesias + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __SHELL_A11Y_H_ +#define __SHELL_A11Y_H_ + +G_BEGIN_DECLS + +void shell_a11y_init (void); + +G_END_DECLS + +#endif /* __SHELL_A11Y_H_ */