Coverage Report

Created: 2018-09-25 14:53

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