Bug 1700051: part 36) Reduce accessibility of `SoftText::mBegin` to `private`. r...
[gecko.git] / accessible / atk / Platform.cpp
blob7908fd7a044670398201a4ef975c5ca5e29ab746
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/. */
7 #include "Platform.h"
9 #include "nsIAccessibleEvent.h"
10 #include "nsIGSettingsService.h"
11 #include "nsMai.h"
12 #include "nsServiceManagerUtils.h"
13 #include "AtkSocketAccessible.h"
14 #include "prenv.h"
15 #include "prlink.h"
17 #ifdef MOZ_ENABLE_DBUS
18 # include <dbus/dbus.h>
19 #endif
20 #include <gtk/gtk.h>
22 using namespace mozilla;
23 using namespace mozilla::a11y;
25 int atkMajorVersion = 1, atkMinorVersion = 12, atkMicroVersion = 0;
27 GType (*gAtkTableCellGetTypeFunc)();
29 extern "C" {
30 typedef GType (*AtkGetTypeType)(void);
31 typedef void (*AtkBridgeAdaptorInit)(int*, char**[]);
34 static PRLibrary* sATKLib = nullptr;
35 static const char sATKLibName[] = "libatk-1.0.so.0";
36 static const char sATKHyperlinkImplGetTypeSymbol[] =
37 "atk_hyperlink_impl_get_type";
39 gboolean toplevel_event_watcher(GSignalInvocationHint*, guint, const GValue*,
40 gpointer);
41 static bool sToplevel_event_hook_added = false;
42 static gulong sToplevel_show_hook = 0;
43 static gulong sToplevel_hide_hook = 0;
45 GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
47 struct AtkBridgeModule {
48 const char* libName;
49 PRLibrary* lib;
50 const char* initName;
51 AtkBridgeAdaptorInit init;
54 static AtkBridgeModule sAtkBridge = {"libatk-bridge-2.0.so.0", nullptr,
55 "atk_bridge_adaptor_init", nullptr};
57 static nsresult LoadGtkModule(AtkBridgeModule& aModule) {
58 NS_ENSURE_ARG(aModule.libName);
60 if (!(aModule.lib = PR_LoadLibrary(aModule.libName))) {
61 return NS_ERROR_FAILURE;
64 // we have loaded the library, try to get the function ptrs
65 if (!(aModule.init = (AtkBridgeAdaptorInit)PR_FindFunctionSymbol(
66 aModule.lib, aModule.initName))) {
67 // fail, :(
68 PR_UnloadLibrary(aModule.lib);
69 aModule.lib = nullptr;
70 return NS_ERROR_FAILURE;
72 return NS_OK;
75 void a11y::PlatformInit() {
76 if (!ShouldA11yBeEnabled()) return;
78 sATKLib = PR_LoadLibrary(sATKLibName);
79 if (!sATKLib) return;
81 AtkGetTypeType pfn_atk_hyperlink_impl_get_type =
82 (AtkGetTypeType)PR_FindFunctionSymbol(sATKLib,
83 sATKHyperlinkImplGetTypeSymbol);
84 if (pfn_atk_hyperlink_impl_get_type) {
85 g_atk_hyperlink_impl_type = pfn_atk_hyperlink_impl_get_type();
88 AtkGetTypeType pfn_atk_socket_get_type =
89 (AtkGetTypeType)PR_FindFunctionSymbol(
90 sATKLib, AtkSocketAccessible::sATKSocketGetTypeSymbol);
91 if (pfn_atk_socket_get_type) {
92 AtkSocketAccessible::g_atk_socket_type = pfn_atk_socket_get_type();
93 AtkSocketAccessible::g_atk_socket_embed =
94 (AtkSocketEmbedType)PR_FindFunctionSymbol(
95 sATKLib, AtkSocketAccessible ::sATKSocketEmbedSymbol);
96 AtkSocketAccessible::gCanEmbed =
97 AtkSocketAccessible::g_atk_socket_type != G_TYPE_INVALID &&
98 AtkSocketAccessible::g_atk_socket_embed;
101 gAtkTableCellGetTypeFunc =
102 (GType(*)())PR_FindFunctionSymbol(sATKLib, "atk_table_cell_get_type");
104 const char* (*atkGetVersion)() =
105 (const char* (*)())PR_FindFunctionSymbol(sATKLib, "atk_get_version");
106 if (atkGetVersion) {
107 const char* version = atkGetVersion();
108 if (version) {
109 char* endPtr = nullptr;
110 atkMajorVersion = strtol(version, &endPtr, 10);
111 if (atkMajorVersion != 0L) {
112 atkMinorVersion = strtol(endPtr + 1, &endPtr, 10);
113 if (atkMinorVersion != 0L) {
114 atkMicroVersion = strtol(endPtr + 1, &endPtr, 10);
120 // Initialize the MAI Utility class, it will overwrite gail_util.
121 g_type_class_unref(g_type_class_ref(mai_util_get_type()));
123 // Init atk-bridge now
124 PR_SetEnv("NO_AT_BRIDGE=0");
125 nsresult rv = LoadGtkModule(sAtkBridge);
126 if (NS_SUCCEEDED(rv)) {
127 (*sAtkBridge.init)(nullptr, nullptr);
130 if (!sToplevel_event_hook_added) {
131 sToplevel_event_hook_added = true;
132 sToplevel_show_hook = g_signal_add_emission_hook(
133 g_signal_lookup("show", GTK_TYPE_WINDOW), 0, toplevel_event_watcher,
134 reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW), nullptr);
135 sToplevel_hide_hook = g_signal_add_emission_hook(
136 g_signal_lookup("hide", GTK_TYPE_WINDOW), 0, toplevel_event_watcher,
137 reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE), nullptr);
141 void a11y::PlatformShutdown() {
142 if (sToplevel_event_hook_added) {
143 sToplevel_event_hook_added = false;
144 g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
145 sToplevel_show_hook);
146 g_signal_remove_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
147 sToplevel_hide_hook);
150 if (sAtkBridge.lib) {
151 // Do not shutdown/unload atk-bridge,
152 // an exit function registered will take care of it
153 // PR_UnloadLibrary(sAtkBridge.lib);
154 sAtkBridge.lib = nullptr;
155 sAtkBridge.init = nullptr;
157 // if (sATKLib) {
158 // PR_UnloadLibrary(sATKLib);
159 // sATKLib = nullptr;
160 // }
163 static const char sAccEnv[] = "GNOME_ACCESSIBILITY";
164 #ifdef MOZ_ENABLE_DBUS
165 static DBusPendingCall* sPendingCall = nullptr;
166 #endif
168 void a11y::PreInit() {
169 #ifdef MOZ_ENABLE_DBUS
170 static bool sChecked = FALSE;
171 if (sChecked) return;
173 sChecked = TRUE;
175 // dbus is only checked if GNOME_ACCESSIBILITY is unset
176 // also make sure that a session bus address is available to prevent dbus from
177 // starting a new one. Dbus confuses the test harness when it creates a new
178 // process (see bug 693343)
179 if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS")) return;
181 DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nullptr);
182 if (!bus) return;
184 dbus_connection_set_exit_on_disconnect(bus, FALSE);
186 static const char* iface = "org.a11y.Status";
187 static const char* member = "IsEnabled";
188 DBusMessage* message;
189 message =
190 dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
191 "org.freedesktop.DBus.Properties", "Get");
192 if (!message) goto dbus_done;
194 dbus_message_append_args(message, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING,
195 &member, DBUS_TYPE_INVALID);
196 dbus_connection_send_with_reply(bus, message, &sPendingCall, 1000);
197 dbus_message_unref(message);
199 dbus_done:
200 dbus_connection_unref(bus);
201 #endif
204 bool a11y::ShouldA11yBeEnabled() {
205 static bool sChecked = false, sShouldEnable = false;
206 if (sChecked) return sShouldEnable;
208 sChecked = true;
210 EPlatformDisabledState disabledState = PlatformDisabledState();
211 if (disabledState == ePlatformIsDisabled) return sShouldEnable = false;
213 // check if accessibility enabled/disabled by environment variable
214 const char* envValue = PR_GetEnv(sAccEnv);
215 if (envValue) return sShouldEnable = !!atoi(envValue);
217 #ifdef MOZ_ENABLE_DBUS
218 PreInit();
219 bool dbusSuccess = false;
220 DBusMessage* reply = nullptr;
221 if (!sPendingCall) goto dbus_done;
223 dbus_pending_call_block(sPendingCall);
224 reply = dbus_pending_call_steal_reply(sPendingCall);
225 dbus_pending_call_unref(sPendingCall);
226 sPendingCall = nullptr;
227 if (!reply ||
228 dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN ||
229 strcmp(dbus_message_get_signature(reply), DBUS_TYPE_VARIANT_AS_STRING)) {
230 goto dbus_done;
233 DBusMessageIter iter, iter_variant, iter_struct;
234 dbus_bool_t dResult;
235 dbus_message_iter_init(reply, &iter);
236 dbus_message_iter_recurse(&iter, &iter_variant);
237 switch (dbus_message_iter_get_arg_type(&iter_variant)) {
238 case DBUS_TYPE_STRUCT:
239 // at-spi2-core 2.2.0-2.2.1 had a bug where it returned a struct
240 dbus_message_iter_recurse(&iter_variant, &iter_struct);
241 if (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_BOOLEAN) {
242 dbus_message_iter_get_basic(&iter_struct, &dResult);
243 sShouldEnable = dResult;
244 dbusSuccess = true;
247 break;
248 case DBUS_TYPE_BOOLEAN:
249 dbus_message_iter_get_basic(&iter_variant, &dResult);
250 sShouldEnable = dResult;
251 dbusSuccess = true;
252 break;
253 default:
254 break;
257 dbus_done:
258 if (reply) dbus_message_unref(reply);
260 if (dbusSuccess) return sShouldEnable;
261 #endif
263 // check GSettings
264 #define GSETINGS_A11Y_INTERFACE "org.gnome.desktop.interface"
265 #define GSETINGS_A11Y_KEY "toolkit-accessibility"
266 nsCOMPtr<nsIGSettingsService> gsettings =
267 do_GetService(NS_GSETTINGSSERVICE_CONTRACTID);
268 nsCOMPtr<nsIGSettingsCollection> a11y_settings;
270 if (gsettings) {
271 gsettings->GetCollectionForSchema(nsLiteralCString(GSETINGS_A11Y_INTERFACE),
272 getter_AddRefs(a11y_settings));
273 if (a11y_settings) {
274 a11y_settings->GetBoolean(nsLiteralCString(GSETINGS_A11Y_KEY),
275 &sShouldEnable);
279 return sShouldEnable;