LCOV - code coverage report
Current view: top level - accessible/atk - Platform.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 44 147 29.9 %
Date: 2017-07-14 16:53:18 Functions: 2 5 40.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "Platform.h"
       8             : 
       9             : #include "nsIAccessibleEvent.h"
      10             : #include "nsIGConfService.h"
      11             : #include "nsIServiceManager.h"
      12             : #include "nsMai.h"
      13             : #include "AtkSocketAccessible.h"
      14             : #include "prenv.h"
      15             : #include "prlink.h"
      16             : 
      17             : #ifdef MOZ_ENABLE_DBUS
      18             : #include <dbus/dbus.h>
      19             : #endif
      20             : #include <gtk/gtk.h>
      21             : 
      22             : #if (MOZ_WIDGET_GTK == 3)
      23             : extern "C" __attribute__((weak,visibility("default"))) int atk_bridge_adaptor_init(int*, char **[]);
      24             : #endif
      25             : 
      26             : using namespace mozilla;
      27             : using namespace mozilla::a11y;
      28             : 
      29             : int atkMajorVersion = 1, atkMinorVersion = 12, atkMicroVersion = 0;
      30             : 
      31             : GType (*gAtkTableCellGetTypeFunc)();
      32             : 
      33             : extern "C" {
      34             : typedef GType (* AtkGetTypeType) (void);
      35             : typedef void (*GnomeAccessibilityInit) (void);
      36             : typedef void (*GnomeAccessibilityShutdown) (void);
      37             : }
      38             : 
      39             : static PRLibrary* sATKLib = nullptr;
      40             : static const char sATKLibName[] = "libatk-1.0.so.0";
      41             : static const char sATKHyperlinkImplGetTypeSymbol[] =
      42             :   "atk_hyperlink_impl_get_type";
      43             : 
      44             : gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*,
      45             :                                 gpointer);
      46             : static bool sToplevel_event_hook_added = false;
      47             : static gulong sToplevel_show_hook = 0;
      48             : static gulong sToplevel_hide_hook = 0;
      49             : 
      50             : GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
      51             : 
      52             : struct GnomeAccessibilityModule
      53             : {
      54             :     const char *libName;
      55             :     PRLibrary *lib;
      56             :     const char *initName;
      57             :     GnomeAccessibilityInit init;
      58             :     const char *shutdownName;
      59             :     GnomeAccessibilityShutdown shutdown;
      60             : };
      61             : 
      62             : static GnomeAccessibilityModule sAtkBridge = {
      63             : #ifdef AIX
      64             :     "libatk-bridge.a(libatk-bridge.so.0)", nullptr,
      65             : #else
      66             :     "libatk-bridge.so", nullptr,
      67             : #endif
      68             :     "gnome_accessibility_module_init", nullptr,
      69             :     "gnome_accessibility_module_shutdown", nullptr
      70             : };
      71             : 
      72             : #if (MOZ_WIDGET_GTK == 2)
      73             : static GnomeAccessibilityModule sGail = {
      74             :     "libgail.so", nullptr,
      75             :     "gnome_accessibility_module_init", nullptr,
      76             :     "gnome_accessibility_module_shutdown", nullptr
      77             : };
      78             : #endif
      79             : 
      80             : static nsresult
      81           0 : LoadGtkModule(GnomeAccessibilityModule& aModule)
      82             : {
      83           0 :     NS_ENSURE_ARG(aModule.libName);
      84             : 
      85           0 :     if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
      86             :         //try to load the module with "gtk-2.0/modules" appended
      87           0 :         char *curLibPath = PR_GetLibraryPath();
      88           0 :         nsAutoCString libPath(curLibPath);
      89             : #if defined(LINUX) && defined(__x86_64__)
      90           0 :         libPath.AppendLiteral(":/usr/lib64:/usr/lib");
      91             : #else
      92             :         libPath.AppendLiteral(":/usr/lib");
      93             : #endif
      94           0 :         PR_FreeLibraryName(curLibPath);
      95             : 
      96           0 :         int16_t loc1 = 0, loc2 = 0;
      97           0 :         int16_t subLen = 0;
      98           0 :         while (loc2 >= 0) {
      99           0 :             loc2 = libPath.FindChar(':', loc1);
     100           0 :             if (loc2 < 0)
     101           0 :                 subLen = libPath.Length() - loc1;
     102             :             else
     103           0 :                 subLen = loc2 - loc1;
     104           0 :             nsAutoCString sub(Substring(libPath, loc1, subLen));
     105             : #if (MOZ_WIDGET_GTK == 2)
     106             :             sub.AppendLiteral("/gtk-2.0/modules/");
     107             : #else
     108           0 :             sub.AppendLiteral("/gtk-3.0/modules/");
     109             : #endif
     110           0 :             sub.Append(aModule.libName);
     111           0 :             aModule.lib = PR_LoadLibrary(sub.get());
     112           0 :             if (aModule.lib)
     113           0 :                 break;
     114             : 
     115           0 :             loc1 = loc2+1;
     116             :         }
     117           0 :         if (!aModule.lib)
     118           0 :             return NS_ERROR_FAILURE;
     119             :     }
     120             : 
     121             :     //we have loaded the library, try to get the function ptrs
     122           0 :     if (!(aModule.init = PR_FindFunctionSymbol(aModule.lib,
     123           0 :                                                aModule.initName)) ||
     124           0 :         !(aModule.shutdown = PR_FindFunctionSymbol(aModule.lib,
     125             :                                                    aModule.shutdownName))) {
     126             : 
     127             :         //fail, :(
     128           0 :         PR_UnloadLibrary(aModule.lib);
     129           0 :         aModule.lib = nullptr;
     130           0 :         return NS_ERROR_FAILURE;
     131             :     }
     132           0 :     return NS_OK;
     133             : }
     134             : 
     135             : void
     136           0 : a11y::PlatformInit()
     137             : {
     138           0 :   if (!ShouldA11yBeEnabled())
     139           0 :     return;
     140             : 
     141           0 :   sATKLib = PR_LoadLibrary(sATKLibName);
     142           0 :   if (!sATKLib)
     143           0 :     return;
     144             : 
     145             :   AtkGetTypeType pfn_atk_hyperlink_impl_get_type =
     146           0 :     (AtkGetTypeType) PR_FindFunctionSymbol(sATKLib, sATKHyperlinkImplGetTypeSymbol);
     147           0 :   if (pfn_atk_hyperlink_impl_get_type)
     148           0 :     g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
     149             : 
     150             :   AtkGetTypeType pfn_atk_socket_get_type = (AtkGetTypeType)
     151           0 :     PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol);
     152           0 :   if (pfn_atk_socket_get_type) {
     153           0 :     AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
     154           0 :     AtkSocketAccessible::g_atk_socket_embed = (AtkSocketEmbedType)
     155           0 :       PR_FindFunctionSymbol(sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
     156           0 :     AtkSocketAccessible::gCanEmbed =
     157           0 :       AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
     158           0 :       AtkSocketAccessible::g_atk_socket_embed;
     159             :   }
     160             : 
     161           0 :   gAtkTableCellGetTypeFunc = (GType (*)())
     162           0 :     PR_FindFunctionSymbol(sATKLib, "atk_table_cell_get_type");
     163             : 
     164             :   const char* (*atkGetVersion)() =
     165           0 :     (const char* (*)()) PR_FindFunctionSymbol(sATKLib, "atk_get_version");
     166           0 :   if (atkGetVersion) {
     167           0 :     const char* version = atkGetVersion();
     168           0 :     if (version) {
     169           0 :       char* endPtr = nullptr;
     170           0 :       atkMajorVersion = strtol(version, &endPtr, 10);
     171           0 :       if (atkMajorVersion != 0L) {
     172           0 :         atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
     173           0 :         if (atkMinorVersion != 0L)
     174           0 :           atkMicroVersion = strtol(endPtr + 1, &endPtr, 10);
     175             :       }
     176             :     }
     177             :   }
     178             : 
     179             : #if (MOZ_WIDGET_GTK == 2)
     180             :   // Load and initialize gail library.
     181             :   nsresult rv = LoadGtkModule(sGail);
     182             :   if (NS_SUCCEEDED(rv))
     183             :     (*sGail.init)();
     184             : #endif
     185             : 
     186             :   // Initialize the MAI Utility class, it will overwrite gail_util.
     187           0 :   g_type_class_unref(g_type_class_ref(mai_util_get_type()));
     188             : 
     189             :   // Init atk-bridge now
     190           0 :   PR_SetEnv("NO_AT_BRIDGE=0");
     191             : #if (MOZ_WIDGET_GTK == 3)
     192           0 :   if (atk_bridge_adaptor_init) {
     193           0 :     atk_bridge_adaptor_init(nullptr, nullptr);
     194             :   } else
     195             : #endif
     196             :   {
     197           0 :     nsresult rv = LoadGtkModule(sAtkBridge);
     198           0 :     if (NS_SUCCEEDED(rv)) {
     199           0 :       (*sAtkBridge.init)();
     200             :     }
     201             :   }
     202             : 
     203           0 :   if (!sToplevel_event_hook_added) {
     204           0 :     sToplevel_event_hook_added = true;
     205           0 :     sToplevel_show_hook =
     206           0 :       g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
     207             :                                  0, toplevel_event_watcher,
     208             :                                  reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW),
     209             :                                  nullptr);
     210           0 :     sToplevel_hide_hook =
     211           0 :       g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0,
     212             :                                  toplevel_event_watcher,
     213             :                                  reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE),
     214             :                                  nullptr);
     215             :   }
     216             : }
     217             : 
     218             : void
     219           0 : a11y::PlatformShutdown()
     220             : {
     221           0 :     if (sToplevel_event_hook_added) {
     222           0 :       sToplevel_event_hook_added = false;
     223           0 :       g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
     224           0 :                                     sToplevel_show_hook);
     225           0 :       g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
     226           0 :                                     sToplevel_hide_hook);
     227             :     }
     228             : 
     229           0 :     if (sAtkBridge.lib) {
     230             :         // Do not shutdown/unload atk-bridge,
     231             :         // an exit function registered will take care of it
     232             :         // if (sAtkBridge.shutdown)
     233             :         //     (*sAtkBridge.shutdown)();
     234             :         // PR_UnloadLibrary(sAtkBridge.lib);
     235           0 :         sAtkBridge.lib = nullptr;
     236           0 :         sAtkBridge.init = nullptr;
     237           0 :         sAtkBridge.shutdown = nullptr;
     238             :     }
     239             : #if (MOZ_WIDGET_GTK == 2)
     240             :     if (sGail.lib) {
     241             :         // Do not shutdown gail because
     242             :         // 1) Maybe it's not init-ed by us. e.g. GtkEmbed
     243             :         // 2) We need it to avoid assert in spi_atk_tidy_windows
     244             :         // if (sGail.shutdown)
     245             :         //   (*sGail.shutdown)();
     246             :         // PR_UnloadLibrary(sGail.lib);
     247             :         sGail.lib = nullptr;
     248             :         sGail.init = nullptr;
     249             :         sGail.shutdown = nullptr;
     250             :     }
     251             : #endif
     252             :     // if (sATKLib) {
     253             :     //     PR_UnloadLibrary(sATKLib);
     254             :     //     sATKLib = nullptr;
     255             :     // }
     256           0 : }
     257             : 
     258             :   static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
     259             : #ifdef MOZ_ENABLE_DBUS
     260             : static DBusPendingCall *sPendingCall = nullptr;
     261             : #endif
     262             : 
     263             : void
     264           3 : a11y::PreInit()
     265             : {
     266             : #ifdef MOZ_ENABLE_DBUS
     267             :   static bool sChecked = FALSE;
     268           3 :   if (sChecked)
     269           2 :     return;
     270             : 
     271           1 :   sChecked = TRUE;
     272             : 
     273             :   // dbus is only checked if GNOME_ACCESSIBILITY is unset
     274             :   // also make sure that a session bus address is available to prevent dbus from
     275             :   // starting a new one.  Dbus confuses the test harness when it creates a new
     276             :   // process (see bug 693343)
     277           1 :   if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
     278           0 :     return;
     279             : 
     280           1 :   DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
     281           1 :   if (!bus)
     282           0 :     return;
     283             : 
     284           1 :   dbus_connection_set_exit_on_disconnect(bus, FALSE);
     285             : 
     286             :   static const char* iface = "org.a11y.Status";
     287             :   static const char* member = "IsEnabled";
     288             :   DBusMessage *message;
     289             :   message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
     290             :                                          "org.freedesktop.DBus.Properties",
     291           1 :                                          "Get");
     292           1 :   if (!message)
     293           0 :     goto dbus_done;
     294             : 
     295             :   dbus_message_append_args(message, DBUS_TYPE_STRING, &iface,
     296           1 :                            DBUS_TYPE_STRING, &member, DBUS_TYPE_INVALID);
     297           1 :   dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000);
     298           1 :   dbus_message_unref(message);
     299             : 
     300             : dbus_done:
     301           1 :   dbus_connection_unref(bus);
     302             : #endif
     303             : }
     304             : 
     305             : bool
     306           3 : a11y::ShouldA11yBeEnabled()
     307             : {
     308             :   static bool sChecked = false, sShouldEnable = false;
     309           3 :   if (sChecked)
     310           2 :     return sShouldEnable;
     311             : 
     312           1 :   sChecked = true;
     313             : 
     314           1 :   EPlatformDisabledState disabledState = PlatformDisabledState();
     315           1 :   if (disabledState == ePlatformIsDisabled)
     316           0 :     return sShouldEnable = false;
     317             : 
     318             :   // check if accessibility enabled/disabled by environment variable
     319           1 :   const char* envValue = PR_GetEnv(sAccEnv);
     320           1 :   if (envValue)
     321           0 :     return sShouldEnable = !!atoi(envValue);
     322             : 
     323             : #ifdef MOZ_ENABLE_DBUS
     324           1 :   PreInit();
     325           1 :   bool dbusSuccess = false;
     326           1 :   DBusMessage *reply = nullptr;
     327           1 :   if (!sPendingCall)
     328           0 :     goto dbus_done;
     329             : 
     330           1 :   dbus_pending_call_block(sPendingCall);
     331           1 :   reply = dbus_pending_call_steal_reply(sPendingCall);
     332           1 :   dbus_pending_call_unref(sPendingCall);
     333           1 :   sPendingCall = nullptr;
     334           2 :   if (!reply ||
     335           2 :       dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN ||
     336           1 :       strcmp(dbus_message_get_signature (reply), DBUS_TYPE_VARIANT_AS_STRING))
     337           0 :     goto dbus_done;
     338             : 
     339             :   DBusMessageIter iter, iter_variant, iter_struct;
     340             :   dbus_bool_t dResult;
     341           1 :   dbus_message_iter_init(reply, &iter);
     342           1 :   dbus_message_iter_recurse (&iter, &iter_variant);
     343           1 :   switch (dbus_message_iter_get_arg_type(&iter_variant)) {
     344             :     case DBUS_TYPE_STRUCT:
     345             :       // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
     346           0 :       dbus_message_iter_recurse(&iter_variant, &iter_struct);
     347           0 :       if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
     348           0 :         dbus_message_iter_get_basic(&iter_struct, &dResult);
     349           0 :         sShouldEnable = dResult;
     350           0 :         dbusSuccess = true;
     351             :       }
     352             : 
     353           0 :       break;
     354             :     case DBUS_TYPE_BOOLEAN:
     355           1 :       dbus_message_iter_get_basic(&iter_variant, &dResult);
     356           1 :       sShouldEnable = dResult;
     357           1 :       dbusSuccess = true;
     358           1 :       break;
     359             :     default:
     360           0 :       break;
     361             :   }
     362             : 
     363             : dbus_done:
     364           1 :   if (reply)
     365           1 :     dbus_message_unref(reply);
     366             : 
     367           1 :   if (dbusSuccess)
     368           1 :     return sShouldEnable;
     369             : #endif
     370             : 
     371             :   //check gconf-2 setting
     372             : #define GCONF_A11Y_KEY "/desktop/gnome/interface/accessibility"
     373           0 :   nsresult rv = NS_OK;
     374             :   nsCOMPtr<nsIGConfService> gconf =
     375           0 :     do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv);
     376           0 :   if (NS_SUCCEEDED(rv) && gconf)
     377           0 :     gconf->GetBool(NS_LITERAL_CSTRING(GCONF_A11Y_KEY), &sShouldEnable);
     378             : 
     379           0 :   return sShouldEnable;
     380             : }

Generated by: LCOV version 1.13