tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ApplicationAccessibleWrap.cpp (5008B)


      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 "ApplicationAccessibleWrap.h"
      8 
      9 #include "nsMai.h"
     10 #include "nsAccessibilityService.h"
     11 
     12 #include <gtk/gtk.h>
     13 #include "atk/atkobject.h"
     14 
     15 using namespace mozilla;
     16 using namespace mozilla::a11y;
     17 
     18 // ApplicationAccessibleWrap
     19 
     20 ApplicationAccessibleWrap::ApplicationAccessibleWrap() = default;
     21 
     22 ApplicationAccessibleWrap::~ApplicationAccessibleWrap() {
     23  AccessibleWrap::ShutdownAtkObject();
     24 }
     25 
     26 gboolean toplevel_event_watcher(GSignalInvocationHint* ihint,
     27                                guint n_param_values,
     28                                const GValue* param_values, gpointer data) {
     29  static GQuark sQuark_gecko_acc_obj = 0;
     30 
     31  if (!sQuark_gecko_acc_obj) {
     32    sQuark_gecko_acc_obj = g_quark_from_static_string("GeckoAccObj");
     33  }
     34 
     35  if (nsAccessibilityService::IsShutdown()) return TRUE;
     36 
     37  GObject* object =
     38      reinterpret_cast<GObject*>(g_value_get_object(param_values));
     39  if (!GTK_IS_WINDOW(object)) return TRUE;
     40 
     41  AtkObject* child = gtk_widget_get_accessible(GTK_WIDGET(object));
     42  AtkRole role = atk_object_get_role(child);
     43 
     44  // GTK native dialog
     45  if (!IS_MAI_OBJECT(child) &&
     46      (role == ATK_ROLE_DIALOG || role == ATK_ROLE_FILE_CHOOSER ||
     47       role == ATK_ROLE_COLOR_CHOOSER || role == ATK_ROLE_FONT_CHOOSER)) {
     48    if (data == reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW)) {
     49      // Attach the dialog accessible to app accessible tree
     50      LocalAccessible* windowAcc =
     51          GetAccService()->AddNativeRootAccessible(child);
     52      g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj,
     53                         reinterpret_cast<gpointer>(windowAcc));
     54 
     55    } else {
     56      // Deattach the dialog accessible
     57      LocalAccessible* windowAcc = reinterpret_cast<LocalAccessible*>(
     58          g_object_get_qdata(G_OBJECT(child), sQuark_gecko_acc_obj));
     59      if (windowAcc) {
     60        GetAccService()->RemoveNativeRootAccessible(windowAcc);
     61        g_object_set_qdata(G_OBJECT(child), sQuark_gecko_acc_obj, nullptr);
     62      }
     63    }
     64  }
     65 
     66  return TRUE;
     67 }
     68 
     69 ENameValueFlag ApplicationAccessibleWrap::DirectName(nsString& aName) const {
     70  // ATK doesn't provide a way to obtain an application name (for example,
     71  // Firefox or Thunderbird) like IA2 does. Thus let's return an application
     72  // name as accessible name that was used to get a branding name (for example,
     73  // Minefield aka nightly Firefox or Daily aka nightly Thunderbird).
     74  AppName(aName);
     75  return eNameOK;
     76 }
     77 
     78 void ApplicationAccessibleWrap::GetNativeInterface(void** aOutAccessible) {
     79  *aOutAccessible = nullptr;
     80 
     81  if (!mAtkObject) {
     82    mAtkObject = reinterpret_cast<AtkObject*>(
     83        g_object_new(MAI_TYPE_ATK_OBJECT, nullptr));
     84    if (!mAtkObject) return;
     85 
     86    atk_object_initialize(mAtkObject, static_cast<Accessible*>(this));
     87    mAtkObject->role = ATK_ROLE_INVALID;
     88    mAtkObject->layer = ATK_LAYER_INVALID;
     89  }
     90 
     91  *aOutAccessible = mAtkObject;
     92 }
     93 
     94 struct AtkRootAccessibleAddedEvent {
     95  AtkObject* app_accessible;
     96  AtkObject* root_accessible;
     97  uint32_t index;
     98 };
     99 
    100 gboolean fireRootAccessibleAddedCB(gpointer data) {
    101  AtkRootAccessibleAddedEvent* eventData = (AtkRootAccessibleAddedEvent*)data;
    102  g_signal_emit_by_name(eventData->app_accessible, "children_changed::add",
    103                        eventData->index, eventData->root_accessible, nullptr);
    104  g_object_unref(eventData->app_accessible);
    105  g_object_unref(eventData->root_accessible);
    106  free(data);
    107 
    108  return FALSE;
    109 }
    110 
    111 bool ApplicationAccessibleWrap::InsertChildAt(uint32_t aIdx,
    112                                              LocalAccessible* aChild) {
    113  if (!ApplicationAccessible::InsertChildAt(aIdx, aChild)) return false;
    114 
    115  AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild);
    116  atk_object_set_parent(atkAccessible, mAtkObject);
    117 
    118  uint32_t count = mChildren.Length();
    119 
    120  // Emit children_changed::add in a timeout
    121  // to make sure aRootAccWrap is fully initialized.
    122  AtkRootAccessibleAddedEvent* eventData =
    123      (AtkRootAccessibleAddedEvent*)malloc(sizeof(AtkRootAccessibleAddedEvent));
    124  if (eventData) {
    125    eventData->app_accessible = mAtkObject;
    126    eventData->root_accessible = atkAccessible;
    127    eventData->index = count - 1;
    128    g_object_ref(mAtkObject);
    129    g_object_ref(atkAccessible);
    130    g_timeout_add(0, fireRootAccessibleAddedCB, eventData);
    131  }
    132 
    133  return true;
    134 }
    135 
    136 bool ApplicationAccessibleWrap::RemoveChild(LocalAccessible* aChild) {
    137  int32_t index = aChild->IndexInParent();
    138 
    139  AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild);
    140  atk_object_set_parent(atkAccessible, nullptr);
    141  g_signal_emit_by_name(mAtkObject, "children_changed::remove", index,
    142                        atkAccessible, nullptr);
    143 
    144  return ApplicationAccessible::RemoveChild(aChild);
    145 }