Skip to content

Commit

Permalink
bug 817133 - move platform init and shutdown stuff out of nsAccessNod…
Browse files Browse the repository at this point in the history
…eWrap and ApplicationAccessibleWrap static methods r=surkov
  • Loading branch information
Trevor Saunders committed Dec 2, 2012
1 parent 6ca590a commit 19b509d
Show file tree
Hide file tree
Showing 31 changed files with 487 additions and 604 deletions.
349 changes: 1 addition & 348 deletions accessible/src/atk/ApplicationAccessibleWrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,127 +8,29 @@

#include "nsCOMPtr.h"
#include "nsMai.h"
#include "prlink.h"
#include "prenv.h"
#include "nsIGConfService.h"
#include "nsIServiceManager.h"
#include "nsAutoPtr.h"
#include "nsAccessibilityService.h"
#include "AtkSocketAccessible.h"

#include <gtk/gtk.h>
#include <atk/atk.h>
#ifdef MOZ_ENABLE_DBUS
#include <dbus/dbus.h>
#endif

using namespace mozilla;
using namespace mozilla::a11y;

typedef GType (* AtkGetTypeType) (void);
GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
static bool sATKChecked = false;
static PRLibrary *sATKLib = nullptr;
static const char sATKLibName[] = "libatk-1.0.so.0";
static const char sATKHyperlinkImplGetTypeSymbol[] =
"atk_hyperlink_impl_get_type";

static bool sToplevel_event_hook_added = false;
static gulong sToplevel_show_hook = 0;
static gulong sToplevel_hide_hook = 0;

G_BEGIN_DECLS
typedef void (*GnomeAccessibilityInit) (void);
typedef void (*GnomeAccessibilityShutdown) (void);
G_END_DECLS

struct GnomeAccessibilityModule
{
const char *libName;
PRLibrary *lib;
const char *initName;
GnomeAccessibilityInit init;
const char *shutdownName;
GnomeAccessibilityShutdown shutdown;
};

static GnomeAccessibilityModule sAtkBridge = {
#ifdef AIX
"libatk-bridge.a(libatk-bridge.so.0)", NULL,
#else
"libatk-bridge.so", NULL,
#endif
"gnome_accessibility_module_init", NULL,
"gnome_accessibility_module_shutdown", NULL
};

static GnomeAccessibilityModule sGail = {
"libgail.so", NULL,
"gnome_accessibility_module_init", NULL,
"gnome_accessibility_module_shutdown", NULL
};

static nsresult LoadGtkModule(GnomeAccessibilityModule& aModule);

static gboolean toplevel_event_watcher(GSignalInvocationHint*, guint,
const GValue*, gpointer);

// ApplicationAccessibleWrap

ApplicationAccessibleWrap::ApplicationAccessibleWrap():
ApplicationAccessible()
{
if (ShouldA11yBeEnabled()) {
// Load and initialize gail library.
nsresult rv = LoadGtkModule(sGail);
if (NS_SUCCEEDED(rv))
(*sGail.init)();
}
}

// XXX we can't do this in ApplicationAccessibleWrap's constructor because
// a11y::ApplicationAcc() will return null then which breaks atk's attempt to
// get the application's root accessible during initialization. this needs to
// be defined here because LoadGtkModule() and the library info is static. See
// bug 817133.
void
nsAccessNodeWrap::InitAccessibility()
{
if (!ShouldA11yBeEnabled())
return;

// 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");
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),
NULL);
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),
NULL);
}
}


ApplicationAccessibleWrap::~ApplicationAccessibleWrap()
{
AccessibleWrap::ShutdownAtkObject();
}

static gboolean
gboolean
toplevel_event_watcher(GSignalInvocationHint* ihint,
guint n_param_values,
const GValue* param_values,
Expand Down Expand Up @@ -176,44 +78,6 @@ toplevel_event_watcher(GSignalInvocationHint* ihint,
return TRUE;
}

void
ApplicationAccessibleWrap::Unload()
{
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 = NULL;
sAtkBridge.init = NULL;
sAtkBridge.shutdown = NULL;
}
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 = NULL;
sGail.init = NULL;
sGail.shutdown = NULL;
}
// if (sATKLib) {
// PR_UnloadLibrary(sATKLib);
// sATKLib = nullptr;
// }
}

ENameValueFlag
ApplicationAccessibleWrap::Name(nsString& aName)
{
Expand Down Expand Up @@ -303,214 +167,3 @@ ApplicationAccessibleWrap::RemoveChild(Accessible* aChild)
return ApplicationAccessible::RemoveChild(aChild);
}

void
ApplicationAccessibleWrap::PreCreate()
{
if (!sATKChecked) {
sATKLib = PR_LoadLibrary(sATKLibName);
if (sATKLib) {
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;
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;
}
}
sATKChecked = true;
}
}

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.Append(":/usr/lib64:/usr/lib");
#else
libPath.Append(":/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));
sub.Append("/gtk-2.0/modules/");
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 = NULL;
return NS_ERROR_FAILURE;
}
return NS_OK;
}

namespace mozilla {
namespace a11y {

static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
#ifdef MOZ_ENABLE_DBUS
static DBusPendingCall *sPendingCall = nullptr;
#endif

void
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
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
static const char sGconfAccessibilityKey[] =
"/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(sGconfAccessibilityKey), &sShouldEnable);

return sShouldEnable;
}
} // namespace a11y
} // namespace mozilla

Loading

0 comments on commit 19b509d

Please sign in to comment.