bug 693343 - a11y disabled in Gnome 3 when GNOME_ACCESSIBILITY is unset patch=mgorse, tbsaunde r=tbsaunde, karlt a=akeybl
authorTrevor Saunders <trev.saunders@gmail.com>
Wed, 04 Jan 2012 20:54:17 -0500
changeset 84224 c0df4333b5b739b584b2b23aaf839409680c886c
parent 84223 c826632d845fcd3f548005935dfb8a97e554ba3e
child 84225 9d5ede8cb11a6a0925f9e33fb87c758ee0657d4d
push id777
push usertrev.saunders@gmail.com
push dateThu, 26 Jan 2012 07:26:41 +0000
treeherdermozilla-aurora@c0df4333b5b7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstbsaunde, karlt, akeybl
bugs693343
milestone11.0a2
bug 693343 - a11y disabled in Gnome 3 when GNOME_ACCESSIBILITY is unset patch=mgorse, tbsaunde r=tbsaunde, karlt a=akeybl
accessible/src/atk/Makefile.in
accessible/src/atk/nsApplicationAccessibleWrap.cpp
accessible/src/base/nsAccessibilityService.h
widget/src/gtk2/nsWindow.cpp
widget/src/gtk2/nsWindow.h
--- a/accessible/src/atk/Makefile.in
+++ b/accessible/src/atk/Makefile.in
@@ -87,15 +87,19 @@ EXPORTS = \
 # we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 CFLAGS		+= $(MOZ_GTK2_CFLAGS)
 CXXFLAGS	+= $(MOZ_GTK2_CFLAGS)
 
+ifdef MOZ_ENABLE_DBUS
+CXXFLAGS += $(MOZ_DBUS_CFLAGS)
+endif
+
 LOCAL_INCLUDES += \
   -I$(srcdir) \
   -I$(srcdir)/../base \
   -I$(srcdir)/../html \
   -I$(srcdir)/../xul \
   -I$(topsrcdir)/other-licenses/atk-1.0 \
   $(NULL)
--- a/accessible/src/atk/nsApplicationAccessibleWrap.cpp
+++ b/accessible/src/atk/nsApplicationAccessibleWrap.cpp
@@ -47,29 +47,30 @@
 #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 = nsnull;
 static const char sATKLibName[] = "libatk-1.0.so.0";
 static const char sATKHyperlinkImplGetTypeSymbol[] =
-    "atk_hyperlink_impl_get_type";
-static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
-static const char sGconfAccessibilityKey[] =
-    "/desktop/gnome/interface/accessibility";
+  "atk_hyperlink_impl_get_type";
 
 /* gail function pointer */
 static guint (* gail_add_global_event_listener) (GSignalEmissionHook listener,
                                                  const gchar *event_type);
 static void (* gail_remove_global_event_listener) (guint remove_listener);
 static void (* gail_remove_key_event_listener) (guint remove_listener);
 static AtkObject * (*gail_get_root) (void);
 
@@ -609,37 +610,17 @@ toplevel_event_watcher(GSignalInvocation
   }
 
   return TRUE;
 }
 
 bool
 nsApplicationAccessibleWrap::Init()
 {
-    // XXX following code is copied from widget/src/gtk2/nsWindow.cpp
-    // we should put it to somewhere that can be used from both modules
-    // see bug 390761
-
-    // check if accessibility enabled/disabled by environment variable
-    bool isGnomeATEnabled = false;
-    const char *envValue = PR_GetEnv(sAccEnv);
-    if (envValue) {
-        isGnomeATEnabled = !!atoi(envValue);
-    } else {
-        //check gconf-2 setting
-      nsresult rv;
-      nsCOMPtr<nsIGConfService> gconf =
-        do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv);
-      if (NS_SUCCEEDED(rv) && gconf) {
-          gconf->GetBool(NS_LITERAL_CSTRING(sGconfAccessibilityKey),
-                         &isGnomeATEnabled);
-      }
-    }
-
-    if (isGnomeATEnabled) {
+    if (ShouldA11yBeEnabled()) {
         // load and initialize gail library
         nsresult rv = LoadGtkModule(sGail);
         if (NS_SUCCEEDED(rv)) {
             (*sGail.init)();
         }
         else {
             MAI_LOG_DEBUG(("Fail to load lib: %s\n", sGail.libName));
         }
@@ -878,8 +859,132 @@ LoadGtkModule(GnomeAccessibilityModule& 
                        aModule.init ? aModule.shutdownName : aModule.initName,
                        aModule.libName));
         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 = nsnull;
+#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
+  if (PR_GetEnv(sAccEnv) || !PR_GetEnv("DBUS_SESSION_BUS_ADDRESS"))
+    return;
+
+  DBusConnection* bus = dbus_bus_get(DBUS_BUS_SESSION, nsnull);
+  if (!bus)
+    return;
+
+  dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+  DBusMessage *message;
+  message = dbus_message_new_method_call("org.a11y.Bus", "/org/a11y/bus",
+                                         "org.freedesktop.DBus.Properties",
+                                         "Get");
+  if (!message)
+    goto dbus_done;
+
+  static const char* iface = "org.a11y.Status";
+  static const char* member = "IsEnabled";
+  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;
+
+  // 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 = nsnull;
+  if (!sPendingCall)
+    goto dbus_done;
+
+  dbus_pending_call_block(sPendingCall);
+  reply = dbus_pending_call_steal_reply(sPendingCall);
+  dbus_pending_call_unref(sPendingCall);
+  sPendingCall = nsnull;
+  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
+
--- a/accessible/src/base/nsAccessibilityService.h
+++ b/accessible/src/base/nsAccessibilityService.h
@@ -51,16 +51,31 @@
 namespace mozilla {
 namespace a11y {
 
 /**
  * Return focus manager.
  */
 FocusManager* FocusMgr();
 
+#ifdef MOZ_ACCESSIBILITY_ATK
+/**
+ * Perform initialization that should be done as soon as possible, in order
+ * to minimize startup time.
+ * XXX: this function and the next defined in nsApplicationAccessibleWrap.cpp
+ */
+void PreInit();
+
+/**
+ * Is platform accessibility enabled.
+ * Only used on linux with atk for now.
+ */
+bool ShouldA11yBeEnabled();
+#endif
+
 } // namespace a11y
 } // namespace mozilla
 
 class nsAccessibilityService : public nsAccDocManager,
                                public mozilla::a11y::FocusManager,
                                public nsIAccessibilityService,
                                public nsIObserver
 {
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -104,29 +104,21 @@
 #include "nsIStringBundle.h"
 #include "nsGfxCIID.h"
 #include "nsIObserverService.h"
 
 #include "nsIdleService.h"
 #include "nsIPropertyBag2.h"
 
 #ifdef ACCESSIBILITY
-#include "nsIAccessibilityService.h"
+#include "nsAccessibilityService.h"
 #include "nsIAccessibleDocument.h"
-#include "prenv.h"
-#include "stdlib.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
-
-static bool sAccessibilityChecked = false;
-/* static */
-bool nsWindow::sAccessibilityEnabled = false;
-static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
-static const char sGconfAccessibilityKey[] = "/desktop/gnome/interface/accessibility";
 #endif
 
 /* For SetIcon */
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsXPIDLString.h"
 #include "nsIFile.h"
 #include "nsILocalFile.h"
 
@@ -1118,19 +1110,18 @@ nsWindow::Show(bool aState)
             NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
                          false);
         } else if (mNeedsResize) {
             NativeResize(mBounds.width, mBounds.height, false);
         }
     }
 
 #ifdef ACCESSIBILITY
-    if (aState && sAccessibilityEnabled) {
+    if (aState && a11y::ShouldA11yBeEnabled())
         CreateRootAccessible();
-    }
 #endif
 
     NativeShow(aState);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -3960,16 +3951,21 @@ nsWindow::Create(nsIWidget        *aPare
     nsIWidget *baseParent = aInitData &&
         (aInitData->mWindowType == eWindowType_dialog ||
          aInitData->mWindowType == eWindowType_toplevel ||
          aInitData->mWindowType == eWindowType_invisible) ?
         nsnull : aParent;
 
     NS_ASSERTION(!mWindowGroup, "already have window group (leaking it)");
 
+#ifdef ACCESSIBILITY
+    // Send a DBus message to check whether a11y is enabled
+    a11y::PreInit();
+#endif
+
     // Ensure that the toolkit is created.
     nsGTKToolkit::GetToolkit();
 
     // initialize all the common bits of this class
     BaseCreate(baseParent, aRect, aHandleEventFunction, aContext, aInitData);
 
     // Do we need to listen for resizes?
     bool listenForResizes = false;;
@@ -4353,41 +4349,16 @@ nsWindow::Create(nsIWidget        *aPare
         LOG(("\tmGdkWindow %p %lx\n", (void *)mGdkWindow,
              gdk_x11_window_get_xid(mGdkWindow)));
     }
 
     // resize so that everything is set to the right dimensions
     if (!mIsTopLevel)
         Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
 
-#ifdef ACCESSIBILITY
-    nsresult rv;
-    if (!sAccessibilityChecked) {
-        sAccessibilityChecked = true;
-
-        //check if accessibility enabled/disabled by environment variable
-        const char *envValue = PR_GetEnv(sAccEnv);
-        if (envValue) {
-            sAccessibilityEnabled = atoi(envValue) != 0;
-            LOG(("Accessibility Env %s=%s\n", sAccEnv, envValue));
-        } else {
-            //check gconf-2 setting
-            nsCOMPtr<nsIGConfService> gconf =
-                do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv); 
-            if (NS_SUCCEEDED(rv) && gconf) {
-
-                // do the work to get gconf setting.
-                // will be done soon later.
-                gconf->GetBool(NS_LITERAL_CSTRING(sGconfAccessibilityKey),
-                               &sAccessibilityEnabled);
-            }
-        }
-    }
-#endif
-
 #ifdef MOZ_DFB
     if (!mDFB) {
          DirectFBCreate( &mDFB );
 
          D_ASSUME( mDFB != NULL );
 
          if (mDFB)
               mDFB->GetDisplayLayer( mDFB, DLID_PRIMARY, &mDFBLayer );
@@ -6557,17 +6528,17 @@ nsWindow::DispatchAccessibleEvent()
     DispatchEvent(&event, status);
 
     return event.mAccessible;
 }
 
 void
 nsWindow::DispatchEventToRootAccessible(PRUint32 aEventType)
 {
-    if (!sAccessibilityEnabled) {
+    if (!a11y::ShouldA11yBeEnabled()) {
         return;
     }
 
     nsCOMPtr<nsIAccessibilityService> accService =
         do_GetService("@mozilla.org/accessibilityService;1");
     if (!accService) {
         return;
     }
--- a/widget/src/gtk2/nsWindow.h
+++ b/widget/src/gtk2/nsWindow.h
@@ -342,19 +342,16 @@ public:
 
     static already_AddRefed<gfxASurface> GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
                                                                   const nsIntSize& aSize);
 #else
     gfxASurface       *GetThebesSurface(cairo_t *cr);
 #endif
     NS_IMETHOD         ReparentNativeWidget(nsIWidget* aNewParent);
 
-#ifdef ACCESSIBILITY
-    static bool        sAccessibilityEnabled;
-#endif
 protected:
     // Helper for SetParent and ReparentNativeWidget.
     void ReparentNativeWidgetInternal(nsIWidget* aNewParent,
                                       GtkWidget* aNewContainer,
                                       GdkWindow* aNewParentWindow,
                                       GtkWidget* aOldContainer);
     nsCOMPtr<nsIWidget> mParent;
     // Is this a toplevel window?