123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "Platform.h"
- #include "nsIAccessibleEvent.h"
- #include "nsIGConfService.h"
- #include "nsIServiceManager.h"
- #include "nsMai.h"
- #include "AtkSocketAccessible.h"
- #include "prenv.h"
- #include "prlink.h"
- #ifdef MOZ_ENABLE_DBUS
- #include <dbus/dbus.h>
- #endif
- #include <gtk/gtk.h>
- #if (MOZ_WIDGET_GTK == 3)
- extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_init(int*, char **[]);
- #endif
- using namespace mozilla;
- using namespace mozilla::a11y;
- int atkMajorVersion = 1, atkMinorVersion = 12;
- GType (*gAtkTableCellGetTypeFunc)();
- extern "C" {
- typedef GType (* AtkGetTypeType) (void);
- typedef void (*GnomeAccessibilityInit) (void);
- typedef void (*GnomeAccessibilityShutdown) (void);
- }
- static PRLibrary* sATKLib = nullptr;
- static const char sATKLibName[] = "libatk-1.0.so.0";
- static const char sATKHyperlinkImplGetTypeSymbol[] =
- "atk_hyperlink_impl_get_type";
- gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*,
- gpointer);
- static bool sToplevel_event_hook_added = false;
- static gulong sToplevel_show_hook = 0;
- static gulong sToplevel_hide_hook = 0;
- GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
- struct GnomeAccessibilityModule
- {
- const char *libName;
- PRLibrary *lib;
- const char *initName;
- GnomeAccessibilityInit init;
- const char *shutdownName;
- GnomeAccessibilityShutdown shutdown;
- };
- static GnomeAccessibilityModule sAtkBridge = {
- "libatk-bridge.so", nullptr,
- "gnome_accessibility_module_init", nullptr,
- "gnome_accessibility_module_shutdown", nullptr
- };
- #if (MOZ_WIDGET_GTK == 2)
- static GnomeAccessibilityModule sGail = {
- "libgail.so", nullptr,
- "gnome_accessibility_module_init", nullptr,
- "gnome_accessibility_module_shutdown", nullptr
- };
- #endif
- static nsresult
- LoadGtkModule(GnomeAccessibilityModule& aModule)
- {
- NS_ENSURE_ARG(aModule.libName);
- if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
- //try to load the module with "gtk-2.0/modules" appended
- char *curLibPath = PR_GetLibraryPath();
- nsAutoCString libPath(curLibPath);
- #if defined(LINUX) && defined(__x86_64__)
- libPath.AppendLiteral(":/usr/lib64:/usr/lib");
- #else
- libPath.AppendLiteral(":/usr/lib");
- #endif
- PR_FreeLibraryName(curLibPath);
- int16_t loc1 = 0, loc2 = 0;
- int16_t subLen = 0;
- while (loc2 >= 0) {
- loc2 = libPath.FindChar(':', loc1);
- if (loc2 < 0)
- subLen = libPath.Length() - loc1;
- else
- subLen = loc2 - loc1;
- nsAutoCString sub(Substring(libPath, loc1, subLen));
- #if (MOZ_WIDGET_GTK == 2)
- sub.AppendLiteral("/gtk-2.0/modules/");
- #else
- sub.AppendLiteral("/gtk-3.0/modules/");
- #endif
- sub.Append(aModule.libName);
- aModule.lib = PR_LoadLibrary(sub.get());
- if (aModule.lib)
- break;
- loc1 = loc2+1;
- }
- if (!aModule.lib)
- return NS_ERROR_FAILURE;
- }
- //we have loaded the library, try to get the function ptrs
- if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
- aModule.initName)) ||
- !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
- aModule.shutdownName))) {
- //fail, :(
- PR_UnloadLibrary(aModule.lib);
- aModule.lib = nullptr;
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
- }
- void
- a11y::PlatformInit()
- {
- if (!ShouldA11yBeEnabled())
- return;
- sATKLib = PR_LoadLibrary(sATKLibName);
- if (!sATKLib)
- return;
- AtkGetTypeType pfn_atk_hyperlink_impl_get_type =
- (AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol);
- if (pfn_atk_hyperlink_impl_get_type)
- g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
- AtkGetTypeType pfn_atk_socket_get_type = (AtkGetTypeType)
- PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol);
- if (pfn_atk_socket_get_type) {
- AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
- AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType)
- PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
- AtkSocketAccessible::gCanEmbed =
- AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
- AtkSocketAccessible::g_atk_socket_embed;
- }
- gAtkTableCellGetTypeFunc = (GType (*)())
- PR_FindFunctionSymbol(sATKLib, "atk_table_cell_get_type");
- const char* (*atkGetVersion)() =
- (const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version");
- if (atkGetVersion) {
- const char* version = atkGetVersion();
- if (version) {
- char* endPtr = nullptr;
- atkMajorVersion = strtol(version, &endPtr, 10);
- if (*endPtr == '.')
- atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
- }
- }
- #if (MOZ_WIDGET_GTK == 2)
- // Load and initialize gail library.
- nsresult rv = LoadGtkModule(sGail);
- if (NS_SUCCEEDED(rv))
- (*sGail.init)();
- #endif
- // Initialize the MAI Utility class, it will overwrite gail_util.
- g_type_class_unref(g_type_class_ref(mai_util_get_type()));
- // Init atk-bridge now
- PR_SetEnv("NO_AT_BRIDGE=0");
- #if (MOZ_WIDGET_GTK == 3)
- if (atk_bridge_adaptor_init) {
- atk_bridge_adaptor_init(nullptr, nullptr);
- } else
- #endif
- {
- nsresult rv = LoadGtkModule(sAtkBridge);
- if (NS_SUCCEEDED(rv)) {
- (*sAtkBridge.init)();
- }
- }
- if (!sToplevel_event_hook_added) {
- sToplevel_event_hook_added = true;
- sToplevel_show_hook =
- g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
- 0, toplevel_event_watcher,
- reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW),
- nullptr);
- sToplevel_hide_hook =
- g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0,
- toplevel_event_watcher,
- reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE),
- nullptr);
- }
- }
- void
- a11y::PlatformShutdown()
- {
- if (sToplevel_event_hook_added) {
- sToplevel_event_hook_added = false;
- g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
- sToplevel_show_hook);
- g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
- sToplevel_hide_hook);
- }
- if (sAtkBridge.lib) {
- // Do not shutdown/unload atk-bridge,
- // an exit function registered will take care of it
- // if (sAtkBridge.shutdown)
- // (*sAtkBridge.shutdown)();
- // PR_UnloadLibrary(sAtkBridge.lib);
- sAtkBridge.lib = nullptr;
- sAtkBridge.init = nullptr;
- sAtkBridge.shutdown = nullptr;
- }
- #if (MOZ_WIDGET_GTK == 2)
- if (sGail.lib) {
- // Do not shutdown gail because
- // 1) Maybe it's not init-ed by us. e.g. GtkEmbed
- // 2) We need it to avoid assert in spi_atk_tidy_windows
- // if (sGail.shutdown)
- // (*sGail.shutdown)();
- // PR_UnloadLibrary(sGail.lib);
- sGail.lib = nullptr;
- sGail.init = nullptr;
- sGail.shutdown = nullptr;
- }
- #endif
- // if (sATKLib) {
- // PR_UnloadLibrary(sATKLib);
- // sATKLib = nullptr;
- // }
- }
- static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
- #ifdef MOZ_ENABLE_DBUS
- static DBusPendingCall *sPendingCall = nullptr;
- #endif
- void
- a11y::PreInit()
- {
- #ifdef MOZ_ENABLE_DBUS
- static bool sChecked = FALSE;
- if (sChecked)
- return;
- sChecked = TRUE;
- // dbus is only checked if GNOME_ACCESSIBILITY is unset
- // also make sure that a session bus address is available to prevent dbus from
- // starting a new one. Dbus confuses the test harness when it creates a new
- // process (see bug 693343)
- if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
- return;
- DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
- if (!bus)
- return;
- dbus_connection_set_exit_on_disconnect(bus, FALSE);
- static const char* iface = "org.a11y.Status";
- static const char* member = "IsEnabled";
- DBusMessage *message;
- message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
- "org.freedesktop.DBus.Properties",
- "Get");
- if (!message)
- goto dbus_done;
- dbus_message_append_args(message, DBUS_TYPE_STRING, &iface,
- DBUS_TYPE_STRING, &member, DBUS_TYPE_INVALID);
- dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000);
- dbus_message_unref(message);
- dbus_done:
- dbus_connection_unref(bus);
- #endif
- }
- bool
- a11y::ShouldA11yBeEnabled()
- {
- static bool sChecked = false, sShouldEnable = false;
- if (sChecked)
- return sShouldEnable;
- sChecked = true;
- EPlatformDisabledState disabledState = PlatformDisabledState();
- if (disabledState == ePlatformIsDisabled)
- return sShouldEnable = false;
- // check if accessibility enabled/disabled by environment variable
- const char* envValue = PR_GetEnv(sAccEnv);
- if (envValue)
- return sShouldEnable = !!atoi(envValue);
- #ifdef MOZ_ENABLE_DBUS
- PreInit();
- bool dbusSuccess = false;
- DBusMessage *reply = nullptr;
- if (!sPendingCall)
- goto dbus_done;
- dbus_pending_call_block(sPendingCall);
- reply = dbus_pending_call_steal_reply(sPendingCall);
- dbus_pending_call_unref(sPendingCall);
- sPendingCall = nullptr;
- if (!reply ||
- dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN ||
- strcmp(dbus_message_get_signature (reply), DBUS_TYPE_VARIANT_AS_STRING))
- goto dbus_done;
- DBusMessageIter iter, iter_variant, iter_struct;
- dbus_bool_t dResult;
- dbus_message_iter_init(reply, &iter);
- dbus_message_iter_recurse (&iter, &iter_variant);
- switch (dbus_message_iter_get_arg_type(&iter_variant)) {
- case DBUS_TYPE_STRUCT:
- // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
- dbus_message_iter_recurse(&iter_variant, &iter_struct);
- if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
- dbus_message_iter_get_basic(&iter_struct, &dResult);
- sShouldEnable = dResult;
- dbusSuccess = true;
- }
- break;
- case DBUS_TYPE_BOOLEAN:
- dbus_message_iter_get_basic(&iter_variant, &dResult);
- sShouldEnable = dResult;
- dbusSuccess = true;
- break;
- default:
- break;
- }
- dbus_done:
- if (reply)
- dbus_message_unref(reply);
- if (dbusSuccess)
- return sShouldEnable;
- #endif
- //check gconf-2 setting
- #define GCONF_A11Y_KEY "/desktop/gnome/interface/accessibility"
- nsresult rv = NS_OK;
- nsCOMPtr<nsIGConfService> gconf =
- do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv);
- if (NS_SUCCEEDED(rv) && gconf)
- gconf->GetBool(NS_LITERAL_CSTRING(GCONF_A11Y_KEY), &sShouldEnable);
- return sShouldEnable;
- }
|