Line data Source code
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 0 : ApplicationAccessibleWrap::ApplicationAccessibleWrap():
23 0 : ApplicationAccessible()
24 : {
25 0 : }
26 :
27 0 : ApplicationAccessibleWrap::~ApplicationAccessibleWrap()
28 : {
29 0 : AccessibleWrap::ShutdownAtkObject();
30 0 : }
31 :
32 : gboolean
33 0 : toplevel_event_watcher(GSignalInvocationHint* ihint,
34 : guint n_param_values,
35 : const GValue* param_values,
36 : gpointer data)
37 : {
38 : static GQuark sQuark_gecko_acc_obj = 0;
39 :
40 0 : if (!sQuark_gecko_acc_obj)
41 0 : sQuark_gecko_acc_obj = g_quark_from_static_string("GeckoAccObj");
42 :
43 0 : if (nsAccessibilityService::IsShutdown())
44 0 : return TRUE;
45 :
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 :
50 0 : AtkObject* child = gtk_widget_get_accessible(GTK_WIDGET(object));
51 :
52 : // GTK native dialog
53 0 : if (!IS_MAI_OBJECT(child) &&
54 0 : (atk_object_get_role(child) == ATK_ROLE_DIALOG)) {
55 :
56 0 : if (data == reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW)) {
57 :
58 : // 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 :
63 : } else {
64 :
65 : // Deattach the dialog accessible
66 : Accessible* windowAcc =
67 : 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 : }
73 :
74 : }
75 : }
76 :
77 0 : return TRUE;
78 : }
79 :
80 : ENameValueFlag
81 0 : ApplicationAccessibleWrap::Name(nsString& aName)
82 : {
83 : // ATK doesn't provide a way to obtain an application name (for example,
84 : // Firefox or Thunderbird) like IA2 does. Thus let's return an application
85 : // name as accessible name that was used to get a branding name (for example,
86 : // Minefield aka nightly Firefox or Daily aka nightly Thunderbird).
87 0 : AppName(aName);
88 0 : return eNameOK;
89 : }
90 :
91 : void
92 0 : ApplicationAccessibleWrap::GetNativeInterface(void** aOutAccessible)
93 : {
94 0 : *aOutAccessible = nullptr;
95 :
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 :
102 0 : atk_object_initialize(mAtkObject, this);
103 0 : mAtkObject->role = ATK_ROLE_INVALID;
104 0 : mAtkObject->layer = ATK_LAYER_INVALID;
105 : }
106 :
107 0 : *aOutAccessible = mAtkObject;
108 : }
109 :
110 : struct AtkRootAccessibleAddedEvent {
111 : AtkObject *app_accessible;
112 : AtkObject *root_accessible;
113 : uint32_t index;
114 : };
115 :
116 0 : gboolean fireRootAccessibleAddedCB(gpointer data)
117 : {
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 :
125 0 : return FALSE;
126 : }
127 :
128 : bool
129 0 : ApplicationAccessibleWrap::InsertChildAt(uint32_t aIdx, Accessible* aChild)
130 : {
131 0 : if (!ApplicationAccessible::InsertChildAt(aIdx, aChild))
132 0 : return false;
133 :
134 0 : AtkObject* atkAccessible = AccessibleWrap::GetAtkObject(aChild);
135 0 : atk_object_set_parent(atkAccessible, mAtkObject);
136 :
137 0 : uint32_t count = mChildren.Length();
138 :
139 : // Emit children_changed::add in a timeout
140 : // to make sure aRootAccWrap is fully initialized.
141 : 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 : }
151 :
152 0 : return true;
153 : }
154 :
155 : bool
156 0 : ApplicationAccessibleWrap::RemoveChild(Accessible* aChild)
157 : {
158 0 : int32_t index = aChild->IndexInParent();
159 :
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 :
165 0 : return ApplicationAccessible::RemoveChild(aChild);
166 : }
167 :
|