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/. */
9 #include "nsIAccessibleEvent.h"
10 #include "nsIGConfService.h"
11 #include "nsIServiceManager.h"
13 #include "AtkSocketAccessible.h"
17 #ifdef MOZ_ENABLE_DBUS
18 #include <dbus/dbus.h>
21 #if (MOZ_WIDGET_GTK == 3)
22 #include <atk-bridge.h>
25 using namespace mozilla
;
26 using namespace mozilla::a11y
;
28 int atkMajorVersion
= 1, atkMinorVersion
= 12;
31 typedef GType (* AtkGetTypeType
) (void);
32 typedef void (*GnomeAccessibilityInit
) (void);
33 typedef void (*GnomeAccessibilityShutdown
) (void);
36 static PRLibrary
* sATKLib
= nullptr;
37 static const char sATKLibName
[] = "libatk-1.0.so.0";
38 static const char sATKHyperlinkImplGetTypeSymbol
[] =
39 "atk_hyperlink_impl_get_type";
41 gboolean
toplevel_event_watcher(GSignalInvocationHint
*, guint
, const GValue
*,
43 static bool sToplevel_event_hook_added
= false;
44 static gulong sToplevel_show_hook
= 0;
45 static gulong sToplevel_hide_hook
= 0;
47 GType g_atk_hyperlink_impl_type
= G_TYPE_INVALID
;
49 #if (MOZ_WIDGET_GTK == 2)
50 struct GnomeAccessibilityModule
55 GnomeAccessibilityInit init
;
56 const char *shutdownName
;
57 GnomeAccessibilityShutdown shutdown
;
60 static GnomeAccessibilityModule sAtkBridge
= {
62 "libatk-bridge.a(libatk-bridge.so.0)", nullptr,
64 "libatk-bridge.so", nullptr,
66 "gnome_accessibility_module_init", nullptr,
67 "gnome_accessibility_module_shutdown", nullptr
70 static GnomeAccessibilityModule sGail
= {
71 "libgail.so", nullptr,
72 "gnome_accessibility_module_init", nullptr,
73 "gnome_accessibility_module_shutdown", nullptr
77 LoadGtkModule(GnomeAccessibilityModule
& aModule
)
79 NS_ENSURE_ARG(aModule
.libName
);
81 if (!(aModule
.lib
= PR_LoadLibrary(aModule
.libName
))) {
82 //try to load the module with "gtk-2.0/modules" appended
83 char *curLibPath
= PR_GetLibraryPath();
84 nsAutoCString
libPath(curLibPath
);
85 #if defined(LINUX) && defined(__x86_64__)
86 libPath
.AppendLiteral(":/usr/lib64:/usr/lib");
88 libPath
.AppendLiteral(":/usr/lib");
90 PR_FreeLibraryName(curLibPath
);
92 int16_t loc1
= 0, loc2
= 0;
95 loc2
= libPath
.FindChar(':', loc1
);
97 subLen
= libPath
.Length() - loc1
;
100 nsAutoCString
sub(Substring(libPath
, loc1
, subLen
));
101 sub
.AppendLiteral("/gtk-2.0/modules/");
102 sub
.Append(aModule
.libName
);
103 aModule
.lib
= PR_LoadLibrary(sub
.get());
110 return NS_ERROR_FAILURE
;
113 //we have loaded the library, try to get the function ptrs
114 if (!(aModule
.init
= PR_FindFunctionSymbol(aModule
.lib
,
115 aModule
.initName
)) ||
116 !(aModule
.shutdown
= PR_FindFunctionSymbol(aModule
.lib
,
117 aModule
.shutdownName
))) {
120 PR_UnloadLibrary(aModule
.lib
);
121 aModule
.lib
= nullptr;
122 return NS_ERROR_FAILURE
;
126 #endif // (MOZ_WIDGET_GTK == 2)
131 if (!ShouldA11yBeEnabled())
134 sATKLib
= PR_LoadLibrary(sATKLibName
);
138 AtkGetTypeType pfn_atk_hyperlink_impl_get_type
=
139 (AtkGetTypeType
) PR_FindFunctionSymbol(sATKLib
, sATKHyperlinkImplGetTypeSymbol
);
140 if (pfn_atk_hyperlink_impl_get_type
)
141 g_atk_hyperlink_impl_type
= pfn_atk_hyperlink_impl_get_type();
143 AtkGetTypeType pfn_atk_socket_get_type
= (AtkGetTypeType
)
144 PR_FindFunctionSymbol(sATKLib
, AtkSocketAccessible::sATKSocketGetTypeSymbol
);
145 if (pfn_atk_socket_get_type
) {
146 AtkSocketAccessible::g_atk_socket_type
= pfn_atk_socket_get_type();
147 AtkSocketAccessible::g_atk_socket_embed
= (AtkSocketEmbedType
)
148 PR_FindFunctionSymbol(sATKLib
, AtkSocketAccessible ::sATKSocketEmbedSymbol
);
149 AtkSocketAccessible::gCanEmbed
=
150 AtkSocketAccessible::g_atk_socket_type
!= G_TYPE_INVALID
&&
151 AtkSocketAccessible::g_atk_socket_embed
;
154 const char* (*atkGetVersion
)() =
155 (const char* (*)()) PR_FindFunctionSymbol(sATKLib
, "atk_get_version");
157 const char* version
= atkGetVersion();
159 char* endPtr
= nullptr;
160 atkMajorVersion
= strtol(version
, &endPtr
, 10);
162 atkMinorVersion
= strtol(endPtr
+ 1, &endPtr
, 10);
166 #if (MOZ_WIDGET_GTK == 2)
167 // Load and initialize gail library.
168 nsresult rv
= LoadGtkModule(sGail
);
169 if (NS_SUCCEEDED(rv
))
173 // Initialize the MAI Utility class, it will overwrite gail_util.
174 g_type_class_unref(g_type_class_ref(mai_util_get_type()));
176 // Init atk-bridge now
177 PR_SetEnv("NO_AT_BRIDGE=0");
178 #if (MOZ_WIDGET_GTK == 2)
179 rv
= LoadGtkModule(sAtkBridge
);
180 if (NS_SUCCEEDED(rv
)) {
181 (*sAtkBridge
.init
)();
184 atk_bridge_adaptor_init(nullptr, nullptr);
187 if (!sToplevel_event_hook_added
) {
188 sToplevel_event_hook_added
= true;
189 sToplevel_show_hook
=
190 g_signal_add_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW
),
191 0, toplevel_event_watcher
,
192 reinterpret_cast<gpointer
>(nsIAccessibleEvent::EVENT_SHOW
),
194 sToplevel_hide_hook
=
195 g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW
), 0,
196 toplevel_event_watcher
,
197 reinterpret_cast<gpointer
>(nsIAccessibleEvent::EVENT_HIDE
),
203 a11y::PlatformShutdown()
205 if (sToplevel_event_hook_added
) {
206 sToplevel_event_hook_added
= false;
207 g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW
),
208 sToplevel_show_hook
);
209 g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW
),
210 sToplevel_hide_hook
);
213 #if (MOZ_WIDGET_GTK == 2)
214 if (sAtkBridge
.lib
) {
215 // Do not shutdown/unload atk-bridge,
216 // an exit function registered will take care of it
217 // if (sAtkBridge.shutdown)
218 // (*sAtkBridge.shutdown)();
219 // PR_UnloadLibrary(sAtkBridge.lib);
220 sAtkBridge
.lib
= nullptr;
221 sAtkBridge
.init
= nullptr;
222 sAtkBridge
.shutdown
= nullptr;
225 // Do not shutdown gail because
226 // 1) Maybe it's not init-ed by us. e.g. GtkEmbed
227 // 2) We need it to avoid assert in spi_atk_tidy_windows
228 // if (sGail.shutdown)
229 // (*sGail.shutdown)();
230 // PR_UnloadLibrary(sGail.lib);
232 sGail
.init
= nullptr;
233 sGail
.shutdown
= nullptr;
237 // PR_UnloadLibrary(sATKLib);
238 // sATKLib = nullptr;
242 static const char sAccEnv
[] = "GNOME_ACCESSIBILITY";
243 #ifdef MOZ_ENABLE_DBUS
244 static DBusPendingCall
*sPendingCall
= nullptr;
250 #ifdef MOZ_ENABLE_DBUS
251 static bool sChecked
= FALSE
;
257 // dbus is only checked if GNOME_ACCESSIBILITY is unset
258 // also make sure that a session bus address is available to prevent dbus from
259 // starting a new one. Dbus confuses the test harness when it creates a new
260 // process (see bug 693343)
261 if (PR_GetEnv(sAccEnv
) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
264 DBusConnection
* bus
= dbus_bus_get(DBUS_BUS_SESSION
, nullptr);
268 dbus_connection_set_exit_on_disconnect(bus
, FALSE
);
270 static const char* iface
= "org.a11y.Status";
271 static const char* member
= "IsEnabled";
272 DBusMessage
*message
;
273 message
= dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
274 "org.freedesktop.DBus.Properties",
279 dbus_message_append_args(message
, DBUS_TYPE_STRING
, &iface
,
280 DBUS_TYPE_STRING
, &member
, DBUS_TYPE_INVALID
);
281 dbus_connection_send_with_reply(bus
, message
, &sPendingCall
, 1000);
282 dbus_message_unref(message
);
285 dbus_connection_unref(bus
);
290 a11y::ShouldA11yBeEnabled()
292 static bool sChecked
= false, sShouldEnable
= false;
294 return sShouldEnable
;
298 EPlatformDisabledState disabledState
= PlatformDisabledState();
299 if (disabledState
== ePlatformIsDisabled
)
300 return sShouldEnable
= false;
302 // check if accessibility enabled/disabled by environment variable
303 const char* envValue
= PR_GetEnv(sAccEnv
);
305 return sShouldEnable
= !!atoi(envValue
);
307 #ifdef MOZ_ENABLE_DBUS
309 bool dbusSuccess
= false;
310 DBusMessage
*reply
= nullptr;
314 dbus_pending_call_block(sPendingCall
);
315 reply
= dbus_pending_call_steal_reply(sPendingCall
);
316 dbus_pending_call_unref(sPendingCall
);
317 sPendingCall
= nullptr;
319 dbus_message_get_type(reply
) != DBUS_MESSAGE_TYPE_METHOD_RETURN
||
320 strcmp(dbus_message_get_signature (reply
), DBUS_TYPE_VARIANT_AS_STRING
))
323 DBusMessageIter iter
, iter_variant
, iter_struct
;
325 dbus_message_iter_init(reply
, &iter
);
326 dbus_message_iter_recurse (&iter
, &iter_variant
);
327 switch (dbus_message_iter_get_arg_type(&iter_variant
)) {
328 case DBUS_TYPE_STRUCT
:
329 // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
330 dbus_message_iter_recurse(&iter_variant
, &iter_struct
);
331 if (dbus_message_iter_get_arg_type(&iter_struct
) == DBUS_TYPE_BOOLEAN
) {
332 dbus_message_iter_get_basic(&iter_struct
, &dResult
);
333 sShouldEnable
= dResult
;
338 case DBUS_TYPE_BOOLEAN
:
339 dbus_message_iter_get_basic(&iter_variant
, &dResult
);
340 sShouldEnable
= dResult
;
349 dbus_message_unref(reply
);
352 return sShouldEnable
;
355 //check gconf-2 setting
356 static const char sGconfAccessibilityKey
[] =
357 "/desktop/gnome/interface/accessibility";
359 nsCOMPtr
<nsIGConfService
> gconf
=
360 do_GetService(NS_GCONFSERVICE_CONTRACTID
, &rv
);
361 if (NS_SUCCEEDED(rv
) && gconf
)
362 gconf
->GetBool(NS_LITERAL_CSTRING(sGconfAccessibilityKey
), &sShouldEnable
);
364 return sShouldEnable
;