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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Sun Microsystems, Inc.
20 : * Portions created by the Initial Developer are Copyright (C) 2002
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Bolian Yin (bolian.yin@sun.com)
25 : * John Sun (john.sun@sun.com)
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "mozilla/Util.h"
42 :
43 : #include "nsAccessible.h"
44 : #include "nsAccessibleWrap.h"
45 :
46 : #include "nsAccUtils.h"
47 : #include "nsApplicationAccessibleWrap.h"
48 : #include "nsIAccessibleRelation.h"
49 : #include "nsRootAccessible.h"
50 : #include "nsDocAccessibleWrap.h"
51 : #include "nsIAccessibleValue.h"
52 : #include "nsString.h"
53 : #include "nsAutoPtr.h"
54 : #include "prprf.h"
55 : #include "nsRoleMap.h"
56 : #include "nsStateMap.h"
57 : #include "Relation.h"
58 : #include "States.h"
59 :
60 : #include "nsMaiInterfaceComponent.h"
61 : #include "nsMaiInterfaceAction.h"
62 : #include "nsMaiInterfaceText.h"
63 : #include "nsMaiInterfaceEditableText.h"
64 : #include "nsMaiInterfaceSelection.h"
65 : #include "nsMaiInterfaceValue.h"
66 : #include "nsMaiInterfaceHypertext.h"
67 : #include "nsMaiInterfaceHyperlinkImpl.h"
68 : #include "nsMaiInterfaceTable.h"
69 : #include "nsXPCOMStrings.h"
70 : #include "nsComponentManagerUtils.h"
71 : #include "nsMaiInterfaceDocument.h"
72 : #include "nsMaiInterfaceImage.h"
73 :
74 : using namespace mozilla;
75 : using namespace mozilla::a11y;
76 :
77 : nsAccessibleWrap::EAvailableAtkSignals nsAccessibleWrap::gAvailableAtkSignals =
78 : eUnknown;
79 :
80 : //defined in nsApplicationAccessibleWrap.cpp
81 : extern "C" GType g_atk_hyperlink_impl_type;
82 :
83 : /* MaiAtkObject */
84 :
85 : enum {
86 : ACTIVATE,
87 : CREATE,
88 : DEACTIVATE,
89 : DESTROY,
90 : MAXIMIZE,
91 : MINIMIZE,
92 : RESIZE,
93 : RESTORE,
94 : LAST_SIGNAL
95 : };
96 :
97 : enum MaiInterfaceType {
98 : MAI_INTERFACE_COMPONENT, /* 0 */
99 : MAI_INTERFACE_ACTION,
100 : MAI_INTERFACE_VALUE,
101 : MAI_INTERFACE_EDITABLE_TEXT,
102 : MAI_INTERFACE_HYPERTEXT,
103 : MAI_INTERFACE_HYPERLINK_IMPL,
104 : MAI_INTERFACE_SELECTION,
105 : MAI_INTERFACE_TABLE,
106 : MAI_INTERFACE_TEXT,
107 : MAI_INTERFACE_DOCUMENT,
108 : MAI_INTERFACE_IMAGE /* 10 */
109 : };
110 :
111 0 : static GType GetAtkTypeForMai(MaiInterfaceType type)
112 : {
113 0 : switch (type) {
114 : case MAI_INTERFACE_COMPONENT:
115 0 : return ATK_TYPE_COMPONENT;
116 : case MAI_INTERFACE_ACTION:
117 0 : return ATK_TYPE_ACTION;
118 : case MAI_INTERFACE_VALUE:
119 0 : return ATK_TYPE_VALUE;
120 : case MAI_INTERFACE_EDITABLE_TEXT:
121 0 : return ATK_TYPE_EDITABLE_TEXT;
122 : case MAI_INTERFACE_HYPERTEXT:
123 0 : return ATK_TYPE_HYPERTEXT;
124 : case MAI_INTERFACE_HYPERLINK_IMPL:
125 0 : return g_atk_hyperlink_impl_type;
126 : case MAI_INTERFACE_SELECTION:
127 0 : return ATK_TYPE_SELECTION;
128 : case MAI_INTERFACE_TABLE:
129 0 : return ATK_TYPE_TABLE;
130 : case MAI_INTERFACE_TEXT:
131 0 : return ATK_TYPE_TEXT;
132 : case MAI_INTERFACE_DOCUMENT:
133 0 : return ATK_TYPE_DOCUMENT;
134 : case MAI_INTERFACE_IMAGE:
135 0 : return ATK_TYPE_IMAGE;
136 : }
137 0 : return G_TYPE_INVALID;
138 : }
139 :
140 : static const char* kNonUserInputEvent = ":system";
141 :
142 : static const GInterfaceInfo atk_if_infos[] = {
143 : {(GInterfaceInitFunc)componentInterfaceInitCB,
144 : (GInterfaceFinalizeFunc) NULL, NULL},
145 : {(GInterfaceInitFunc)actionInterfaceInitCB,
146 : (GInterfaceFinalizeFunc) NULL, NULL},
147 : {(GInterfaceInitFunc)valueInterfaceInitCB,
148 : (GInterfaceFinalizeFunc) NULL, NULL},
149 : {(GInterfaceInitFunc)editableTextInterfaceInitCB,
150 : (GInterfaceFinalizeFunc) NULL, NULL},
151 : {(GInterfaceInitFunc)hypertextInterfaceInitCB,
152 : (GInterfaceFinalizeFunc) NULL, NULL},
153 : {(GInterfaceInitFunc)hyperlinkImplInterfaceInitCB,
154 : (GInterfaceFinalizeFunc) NULL, NULL},
155 : {(GInterfaceInitFunc)selectionInterfaceInitCB,
156 : (GInterfaceFinalizeFunc) NULL, NULL},
157 : {(GInterfaceInitFunc)tableInterfaceInitCB,
158 : (GInterfaceFinalizeFunc) NULL, NULL},
159 : {(GInterfaceInitFunc)textInterfaceInitCB,
160 : (GInterfaceFinalizeFunc) NULL, NULL},
161 : {(GInterfaceInitFunc)documentInterfaceInitCB,
162 : (GInterfaceFinalizeFunc) NULL, NULL},
163 : {(GInterfaceInitFunc)imageInterfaceInitCB,
164 : (GInterfaceFinalizeFunc) NULL, NULL}
165 : };
166 :
167 : /**
168 : * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject
169 : */
170 : struct MaiAtkObject
171 : {
172 : AtkObject parent;
173 : /*
174 : * The nsAccessibleWrap whose properties and features are exported
175 : * via this object instance.
176 : */
177 : nsAccessibleWrap *accWrap;
178 : };
179 :
180 : struct MaiAtkObjectClass
181 : {
182 : AtkObjectClass parent_class;
183 : };
184 :
185 : static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
186 :
187 : #ifdef MAI_LOGGING
188 : PRInt32 sMaiAtkObjCreated = 0;
189 : PRInt32 sMaiAtkObjDeleted = 0;
190 : #endif
191 :
192 : G_BEGIN_DECLS
193 : /* callbacks for MaiAtkObject */
194 : static void classInitCB(AtkObjectClass *aClass);
195 : static void initializeCB(AtkObject *aAtkObj, gpointer aData);
196 : static void finalizeCB(GObject *aObj);
197 :
198 : /* callbacks for AtkObject virtual functions */
199 : static const gchar* getNameCB (AtkObject *aAtkObj);
200 : /* getDescriptionCB is also used by image interface */
201 : const gchar* getDescriptionCB (AtkObject *aAtkObj);
202 : static AtkRole getRoleCB(AtkObject *aAtkObj);
203 : static AtkAttributeSet* getAttributesCB(AtkObject *aAtkObj);
204 : static AtkObject* getParentCB(AtkObject *aAtkObj);
205 : static gint getChildCountCB(AtkObject *aAtkObj);
206 : static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex);
207 : static gint getIndexInParentCB(AtkObject *aAtkObj);
208 : static AtkStateSet* refStateSetCB(AtkObject *aAtkObj);
209 : static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj);
210 :
211 : /* the missing atkobject virtual functions */
212 : /*
213 : static AtkLayer getLayerCB(AtkObject *aAtkObj);
214 : static gint getMdiZorderCB(AtkObject *aAtkObj);
215 : static void SetNameCB(AtkObject *aAtkObj,
216 : const gchar *name);
217 : static void SetDescriptionCB(AtkObject *aAtkObj,
218 : const gchar *description);
219 : static void SetParentCB(AtkObject *aAtkObj,
220 : AtkObject *parent);
221 : static void SetRoleCB(AtkObject *aAtkObj,
222 : AtkRole role);
223 : static guint ConnectPropertyChangeHandlerCB(
224 : AtkObject *aObj,
225 : AtkPropertyChangeHandler *handler);
226 : static void RemovePropertyChangeHandlerCB(
227 : AtkObject *aAtkObj,
228 : guint handler_id);
229 : static void InitializeCB(AtkObject *aAtkObj,
230 : gpointer data);
231 : static void ChildrenChangedCB(AtkObject *aAtkObj,
232 : guint change_index,
233 : gpointer changed_child);
234 : static void FocusEventCB(AtkObject *aAtkObj,
235 : gboolean focus_in);
236 : static void PropertyChangeCB(AtkObject *aAtkObj,
237 : AtkPropertyValues *values);
238 : static void StateChangeCB(AtkObject *aAtkObj,
239 : const gchar *name,
240 : gboolean state_set);
241 : static void VisibleDataChangedCB(AtkObject *aAtkObj);
242 : */
243 : G_END_DECLS
244 :
245 : static GType GetMaiAtkType(PRUint16 interfacesBits);
246 : static const char * GetUniqueMaiAtkTypeName(PRUint16 interfacesBits);
247 :
248 : static gpointer parent_class = NULL;
249 :
250 : static GQuark quark_mai_hyperlink = 0;
251 :
252 : GType
253 0 : mai_atk_object_get_type(void)
254 : {
255 : static GType type = 0;
256 :
257 0 : if (!type) {
258 : static const GTypeInfo tinfo = {
259 : sizeof(MaiAtkObjectClass),
260 : (GBaseInitFunc)NULL,
261 : (GBaseFinalizeFunc)NULL,
262 : (GClassInitFunc)classInitCB,
263 : (GClassFinalizeFunc)NULL,
264 : NULL, /* class data */
265 : sizeof(MaiAtkObject), /* instance size */
266 : 0, /* nb preallocs */
267 : (GInstanceInitFunc)NULL,
268 : NULL /* value table */
269 : };
270 :
271 : type = g_type_register_static(ATK_TYPE_OBJECT,
272 0 : "MaiAtkObject", &tinfo, GTypeFlags(0));
273 0 : quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink");
274 : }
275 0 : return type;
276 : }
277 :
278 : #ifdef MAI_LOGGING
279 : PRInt32 nsAccessibleWrap::mAccWrapCreated = 0;
280 : PRInt32 nsAccessibleWrap::mAccWrapDeleted = 0;
281 : #endif
282 :
283 0 : nsAccessibleWrap::
284 : nsAccessibleWrap(nsIContent* aContent, nsDocAccessible* aDoc) :
285 0 : nsAccessible(aContent, aDoc), mAtkObject(nsnull)
286 : {
287 : #ifdef MAI_LOGGING
288 0 : ++mAccWrapCreated;
289 : #endif
290 0 : MAI_LOG_DEBUG(("==nsAccessibleWrap creating: this=%p,total=%d left=%d\n",
291 : (void*)this, mAccWrapCreated,
292 : (mAccWrapCreated-mAccWrapDeleted)));
293 0 : }
294 :
295 0 : nsAccessibleWrap::~nsAccessibleWrap()
296 : {
297 0 : NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called");
298 :
299 : #ifdef MAI_LOGGING
300 0 : ++mAccWrapDeleted;
301 : #endif
302 0 : MAI_LOG_DEBUG(("==nsAccessibleWrap deleting: this=%p,total=%d left=%d\n",
303 : (void*)this, mAccWrapDeleted,
304 : (mAccWrapCreated-mAccWrapDeleted)));
305 0 : }
306 :
307 0 : void nsAccessibleWrap::ShutdownAtkObject()
308 : {
309 0 : if (mAtkObject) {
310 0 : if (IS_MAI_OBJECT(mAtkObject)) {
311 0 : MAI_ATK_OBJECT(mAtkObject)->accWrap = nsnull;
312 : }
313 0 : SetMaiHyperlink(nsnull);
314 0 : g_object_unref(mAtkObject);
315 0 : mAtkObject = nsnull;
316 : }
317 0 : }
318 :
319 : void
320 0 : nsAccessibleWrap::Shutdown()
321 : {
322 0 : ShutdownAtkObject();
323 0 : nsAccessible::Shutdown();
324 0 : }
325 :
326 0 : MaiHyperlink* nsAccessibleWrap::GetMaiHyperlink(bool aCreate /* = true */)
327 : {
328 : // make sure mAtkObject is created
329 0 : GetAtkObject();
330 :
331 0 : NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
332 0 : NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject");
333 0 : MaiHyperlink* maiHyperlink = nsnull;
334 0 : if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) {
335 0 : maiHyperlink = (MaiHyperlink*)g_object_get_qdata(G_OBJECT(mAtkObject),
336 0 : quark_mai_hyperlink);
337 0 : if (!maiHyperlink && aCreate) {
338 0 : maiHyperlink = new MaiHyperlink(this);
339 0 : SetMaiHyperlink(maiHyperlink);
340 : }
341 : }
342 0 : return maiHyperlink;
343 : }
344 :
345 0 : void nsAccessibleWrap::SetMaiHyperlink(MaiHyperlink* aMaiHyperlink)
346 : {
347 0 : NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
348 0 : NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject");
349 0 : if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) {
350 0 : MaiHyperlink* maiHyperlink = GetMaiHyperlink(false);
351 0 : if (!maiHyperlink && !aMaiHyperlink) {
352 0 : return; // Never set and we're shutting down
353 : }
354 0 : delete maiHyperlink;
355 0 : g_object_set_qdata(G_OBJECT(mAtkObject), quark_mai_hyperlink,
356 0 : aMaiHyperlink);
357 : }
358 : }
359 :
360 0 : NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible)
361 : {
362 0 : *aOutAccessible = nsnull;
363 :
364 0 : if (!mAtkObject) {
365 0 : if (IsDefunct() || !nsAccUtils::IsEmbeddedObject(this)) {
366 : // We don't create ATK objects for node which has been shutdown, or
367 : // nsIAccessible plain text leaves
368 0 : return NS_ERROR_FAILURE;
369 : }
370 :
371 0 : GType type = GetMaiAtkType(CreateMaiInterfaces());
372 0 : NS_ENSURE_TRUE(type, NS_ERROR_FAILURE);
373 : mAtkObject =
374 : reinterpret_cast<AtkObject *>
375 0 : (g_object_new(type, NULL));
376 0 : NS_ENSURE_TRUE(mAtkObject, NS_ERROR_OUT_OF_MEMORY);
377 :
378 0 : atk_object_initialize(mAtkObject, this);
379 0 : mAtkObject->role = ATK_ROLE_INVALID;
380 0 : mAtkObject->layer = ATK_LAYER_INVALID;
381 : }
382 :
383 0 : *aOutAccessible = mAtkObject;
384 0 : return NS_OK;
385 : }
386 :
387 : AtkObject *
388 0 : nsAccessibleWrap::GetAtkObject(void)
389 : {
390 0 : void *atkObj = nsnull;
391 0 : GetNativeInterface(&atkObj);
392 0 : return static_cast<AtkObject *>(atkObj);
393 : }
394 :
395 : // Get AtkObject from nsIAccessible interface
396 : /* static */
397 : AtkObject *
398 0 : nsAccessibleWrap::GetAtkObject(nsIAccessible * acc)
399 : {
400 0 : void *atkObjPtr = nsnull;
401 0 : acc->GetNativeInterface(&atkObjPtr);
402 0 : return atkObjPtr ? ATK_OBJECT(atkObjPtr) : nsnull;
403 : }
404 :
405 : /* private */
406 : PRUint16
407 0 : nsAccessibleWrap::CreateMaiInterfaces(void)
408 : {
409 0 : PRUint16 interfacesBits = 0;
410 :
411 : // Add Interfaces for each nsIAccessible.ext interfaces
412 :
413 : // the Component interface are supported by all nsIAccessible
414 0 : interfacesBits |= 1 << MAI_INTERFACE_COMPONENT;
415 :
416 : // Add Action interface if the action count is more than zero.
417 0 : if (ActionCount() > 0)
418 0 : interfacesBits |= 1 << MAI_INTERFACE_ACTION;
419 :
420 : //nsIAccessibleText
421 0 : nsCOMPtr<nsIAccessibleText> accessInterfaceText;
422 : QueryInterface(NS_GET_IID(nsIAccessibleText),
423 0 : getter_AddRefs(accessInterfaceText));
424 0 : if (accessInterfaceText) {
425 0 : interfacesBits |= 1 << MAI_INTERFACE_TEXT;
426 : }
427 :
428 : //nsIAccessibleEditableText
429 0 : nsCOMPtr<nsIAccessibleEditableText> accessInterfaceEditableText;
430 : QueryInterface(NS_GET_IID(nsIAccessibleEditableText),
431 0 : getter_AddRefs(accessInterfaceEditableText));
432 0 : if (accessInterfaceEditableText) {
433 0 : interfacesBits |= 1 << MAI_INTERFACE_EDITABLE_TEXT;
434 : }
435 :
436 : //nsIAccessibleValue
437 0 : nsCOMPtr<nsIAccessibleValue> accessInterfaceValue;
438 : QueryInterface(NS_GET_IID(nsIAccessibleValue),
439 0 : getter_AddRefs(accessInterfaceValue));
440 0 : if (accessInterfaceValue) {
441 0 : interfacesBits |= 1 << MAI_INTERFACE_VALUE;
442 : }
443 :
444 : // document accessible
445 0 : if (IsDoc())
446 0 : interfacesBits |= 1 << MAI_INTERFACE_DOCUMENT;
447 :
448 0 : if (IsImageAccessible())
449 0 : interfacesBits |= 1 << MAI_INTERFACE_IMAGE;
450 :
451 : // HyperLinkAccessible
452 0 : if (IsLink())
453 0 : interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
454 :
455 0 : if (!nsAccUtils::MustPrune(this)) { // These interfaces require children
456 : //nsIAccessibleHypertext
457 0 : if (IsHyperText()) {
458 0 : interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT;
459 : }
460 :
461 : //nsIAccessibleTable
462 0 : nsCOMPtr<nsIAccessibleTable> accessInterfaceTable;
463 : QueryInterface(NS_GET_IID(nsIAccessibleTable),
464 0 : getter_AddRefs(accessInterfaceTable));
465 0 : if (accessInterfaceTable) {
466 0 : interfacesBits |= 1 << MAI_INTERFACE_TABLE;
467 : }
468 :
469 : //nsIAccessibleSelection
470 0 : if (IsSelect()) {
471 0 : interfacesBits |= 1 << MAI_INTERFACE_SELECTION;
472 : }
473 : }
474 :
475 0 : return interfacesBits;
476 : }
477 :
478 : static GType
479 0 : GetMaiAtkType(PRUint16 interfacesBits)
480 : {
481 : GType type;
482 : static const GTypeInfo tinfo = {
483 : sizeof(MaiAtkObjectClass),
484 : (GBaseInitFunc) NULL,
485 : (GBaseFinalizeFunc) NULL,
486 : (GClassInitFunc) NULL,
487 : (GClassFinalizeFunc) NULL,
488 : NULL, /* class data */
489 : sizeof(MaiAtkObject), /* instance size */
490 : 0, /* nb preallocs */
491 : (GInstanceInitFunc) NULL,
492 : NULL /* value table */
493 : };
494 :
495 : /*
496 : * The members we use to register GTypes are GetAtkTypeForMai
497 : * and atk_if_infos, which are constant values to each MaiInterface
498 : * So we can reuse the registered GType when having
499 : * the same MaiInterface types.
500 : */
501 0 : const char *atkTypeName = GetUniqueMaiAtkTypeName(interfacesBits);
502 0 : type = g_type_from_name(atkTypeName);
503 0 : if (type) {
504 0 : return type;
505 : }
506 :
507 : /*
508 : * gobject limits the number of types that can directly derive from any
509 : * given object type to 4095.
510 : */
511 : static PRUint16 typeRegCount = 0;
512 0 : if (typeRegCount++ >= 4095) {
513 0 : return G_TYPE_INVALID;
514 : }
515 : type = g_type_register_static(MAI_TYPE_ATK_OBJECT,
516 : atkTypeName,
517 0 : &tinfo, GTypeFlags(0));
518 :
519 0 : for (PRUint32 index = 0; index < ArrayLength(atk_if_infos); index++) {
520 0 : if (interfacesBits & (1 << index)) {
521 : g_type_add_interface_static(type,
522 : GetAtkTypeForMai((MaiInterfaceType)index),
523 0 : &atk_if_infos[index]);
524 : }
525 : }
526 :
527 0 : return type;
528 : }
529 :
530 : static const char *
531 0 : GetUniqueMaiAtkTypeName(PRUint16 interfacesBits)
532 : {
533 : #define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(PRUint16)*8/4+1 < 30 */
534 :
535 : static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */
536 : static gchar name[MAI_ATK_TYPE_NAME_LEN + 1];
537 :
538 : PR_snprintf(name, MAI_ATK_TYPE_NAME_LEN, "%s%x", namePrefix,
539 0 : interfacesBits);
540 0 : name[MAI_ATK_TYPE_NAME_LEN] = '\0';
541 :
542 0 : MAI_LOG_DEBUG(("MaiWidget::LastedTypeName=%s\n", name));
543 :
544 0 : return name;
545 : }
546 :
547 0 : bool nsAccessibleWrap::IsValidObject()
548 : {
549 : // to ensure we are not shut down
550 0 : return !IsDefunct();
551 : }
552 :
553 : /* static functions for ATK callbacks */
554 : void
555 0 : classInitCB(AtkObjectClass *aClass)
556 : {
557 0 : GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
558 :
559 0 : parent_class = g_type_class_peek_parent(aClass);
560 :
561 0 : aClass->get_name = getNameCB;
562 0 : aClass->get_description = getDescriptionCB;
563 0 : aClass->get_parent = getParentCB;
564 0 : aClass->get_n_children = getChildCountCB;
565 0 : aClass->ref_child = refChildCB;
566 0 : aClass->get_index_in_parent = getIndexInParentCB;
567 0 : aClass->get_role = getRoleCB;
568 0 : aClass->get_attributes = getAttributesCB;
569 0 : aClass->ref_state_set = refStateSetCB;
570 0 : aClass->ref_relation_set = refRelationSetCB;
571 :
572 0 : aClass->initialize = initializeCB;
573 :
574 0 : gobject_class->finalize = finalizeCB;
575 :
576 : mai_atk_object_signals [ACTIVATE] =
577 : g_signal_new ("activate",
578 : MAI_TYPE_ATK_OBJECT,
579 : G_SIGNAL_RUN_LAST,
580 : 0, /* default signal handler */
581 : NULL, NULL,
582 : g_cclosure_marshal_VOID__VOID,
583 0 : G_TYPE_NONE, 0);
584 : mai_atk_object_signals [CREATE] =
585 : g_signal_new ("create",
586 : MAI_TYPE_ATK_OBJECT,
587 : G_SIGNAL_RUN_LAST,
588 : 0, /* default signal handler */
589 : NULL, NULL,
590 : g_cclosure_marshal_VOID__VOID,
591 0 : G_TYPE_NONE, 0);
592 : mai_atk_object_signals [DEACTIVATE] =
593 : g_signal_new ("deactivate",
594 : MAI_TYPE_ATK_OBJECT,
595 : G_SIGNAL_RUN_LAST,
596 : 0, /* default signal handler */
597 : NULL, NULL,
598 : g_cclosure_marshal_VOID__VOID,
599 0 : G_TYPE_NONE, 0);
600 : mai_atk_object_signals [DESTROY] =
601 : g_signal_new ("destroy",
602 : MAI_TYPE_ATK_OBJECT,
603 : G_SIGNAL_RUN_LAST,
604 : 0, /* default signal handler */
605 : NULL, NULL,
606 : g_cclosure_marshal_VOID__VOID,
607 0 : G_TYPE_NONE, 0);
608 : mai_atk_object_signals [MAXIMIZE] =
609 : g_signal_new ("maximize",
610 : MAI_TYPE_ATK_OBJECT,
611 : G_SIGNAL_RUN_LAST,
612 : 0, /* default signal handler */
613 : NULL, NULL,
614 : g_cclosure_marshal_VOID__VOID,
615 0 : G_TYPE_NONE, 0);
616 : mai_atk_object_signals [MINIMIZE] =
617 : g_signal_new ("minimize",
618 : MAI_TYPE_ATK_OBJECT,
619 : G_SIGNAL_RUN_LAST,
620 : 0, /* default signal handler */
621 : NULL, NULL,
622 : g_cclosure_marshal_VOID__VOID,
623 0 : G_TYPE_NONE, 0);
624 : mai_atk_object_signals [RESIZE] =
625 : g_signal_new ("resize",
626 : MAI_TYPE_ATK_OBJECT,
627 : G_SIGNAL_RUN_LAST,
628 : 0, /* default signal handler */
629 : NULL, NULL,
630 : g_cclosure_marshal_VOID__VOID,
631 0 : G_TYPE_NONE, 0);
632 : mai_atk_object_signals [RESTORE] =
633 : g_signal_new ("restore",
634 : MAI_TYPE_ATK_OBJECT,
635 : G_SIGNAL_RUN_LAST,
636 : 0, /* default signal handler */
637 : NULL, NULL,
638 : g_cclosure_marshal_VOID__VOID,
639 0 : G_TYPE_NONE, 0);
640 :
641 0 : }
642 :
643 : void
644 0 : initializeCB(AtkObject *aAtkObj, gpointer aData)
645 : {
646 0 : NS_ASSERTION((IS_MAI_OBJECT(aAtkObj)), "Invalid AtkObject");
647 0 : NS_ASSERTION(aData, "Invalid Data to init AtkObject");
648 0 : if (!aAtkObj || !aData)
649 0 : return;
650 :
651 : /* call parent init function */
652 : /* AtkObjectClass has not a "initialize" function now,
653 : * maybe it has later
654 : */
655 :
656 0 : if (ATK_OBJECT_CLASS(parent_class)->initialize)
657 0 : ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
658 :
659 : /* initialize object */
660 0 : MAI_ATK_OBJECT(aAtkObj)->accWrap =
661 0 : static_cast<nsAccessibleWrap*>(aData);
662 :
663 : #ifdef MAI_LOGGING
664 0 : ++sMaiAtkObjCreated;
665 : #endif
666 0 : MAI_LOG_DEBUG(("MaiAtkObj Create obj=%p for AccWrap=%p, all=%d, left=%d\n",
667 : (void*)aAtkObj, (void*)aData, sMaiAtkObjCreated,
668 : (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
669 : }
670 :
671 : void
672 0 : finalizeCB(GObject *aObj)
673 : {
674 0 : if (!IS_MAI_OBJECT(aObj))
675 0 : return;
676 0 : NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nsnull, "AccWrap NOT null");
677 :
678 : #ifdef MAI_LOGGING
679 0 : ++sMaiAtkObjDeleted;
680 : #endif
681 0 : MAI_LOG_DEBUG(("MaiAtkObj Delete obj=%p, all=%d, left=%d\n",
682 : (void*)aObj, sMaiAtkObjCreated,
683 : (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
684 :
685 : // call parent finalize function
686 : // finalize of GObjectClass will unref the accessible parent if has
687 0 : if (G_OBJECT_CLASS (parent_class)->finalize)
688 0 : G_OBJECT_CLASS (parent_class)->finalize(aObj);
689 : }
690 :
691 : const gchar *
692 0 : getNameCB(AtkObject *aAtkObj)
693 : {
694 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
695 0 : if (!accWrap) {
696 0 : return nsnull;
697 : }
698 :
699 : /* nsIAccessible is responsible for the non-NULL name */
700 0 : nsAutoString uniName;
701 0 : nsresult rv = accWrap->GetName(uniName);
702 0 : NS_ENSURE_SUCCESS(rv, nsnull);
703 :
704 0 : NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
705 0 : if (!uniName.Equals(objName)) {
706 : atk_object_set_name(aAtkObj,
707 0 : NS_ConvertUTF16toUTF8(uniName).get());
708 : }
709 0 : return aAtkObj->name;
710 : }
711 :
712 : const gchar *
713 0 : getDescriptionCB(AtkObject *aAtkObj)
714 : {
715 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
716 0 : if (!accWrap || accWrap->IsDefunct())
717 0 : return nsnull;
718 :
719 : /* nsIAccessible is responsible for the non-NULL description */
720 0 : nsAutoString uniDesc;
721 0 : accWrap->Description(uniDesc);
722 :
723 0 : NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description);
724 0 : if (!uniDesc.Equals(objDesc))
725 : atk_object_set_description(aAtkObj,
726 0 : NS_ConvertUTF16toUTF8(uniDesc).get());
727 :
728 0 : return aAtkObj->description;
729 : }
730 :
731 : AtkRole
732 0 : getRoleCB(AtkObject *aAtkObj)
733 : {
734 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
735 0 : if (!accWrap) {
736 0 : return ATK_ROLE_INVALID;
737 : }
738 :
739 : #ifdef DEBUG_A11Y
740 : NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
741 : "Does not support nsIAccessibleText when it should");
742 : #endif
743 :
744 0 : if (aAtkObj->role == ATK_ROLE_INVALID) {
745 : // map to the actual value
746 0 : PRUint32 atkRole = atkRoleMap[accWrap->Role()];
747 0 : NS_ASSERTION(atkRoleMap[nsIAccessibleRole::ROLE_LAST_ENTRY] ==
748 : kROLE_ATK_LAST_ENTRY, "ATK role map skewed");
749 0 : aAtkObj->role = static_cast<AtkRole>(atkRole);
750 : }
751 0 : return aAtkObj->role;
752 : }
753 :
754 : AtkAttributeSet*
755 0 : ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes)
756 : {
757 0 : if (!aAttributes)
758 0 : return nsnull;
759 :
760 0 : AtkAttributeSet *objAttributeSet = nsnull;
761 0 : nsCOMPtr<nsISimpleEnumerator> propEnum;
762 0 : nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
763 0 : NS_ENSURE_SUCCESS(rv, nsnull);
764 :
765 : bool hasMore;
766 0 : while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
767 0 : nsCOMPtr<nsISupports> sup;
768 0 : rv = propEnum->GetNext(getter_AddRefs(sup));
769 0 : NS_ENSURE_SUCCESS(rv, objAttributeSet);
770 :
771 0 : nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
772 0 : NS_ENSURE_TRUE(propElem, objAttributeSet);
773 :
774 0 : nsCAutoString name;
775 0 : rv = propElem->GetKey(name);
776 0 : NS_ENSURE_SUCCESS(rv, objAttributeSet);
777 :
778 0 : nsAutoString value;
779 0 : rv = propElem->GetValue(value);
780 0 : NS_ENSURE_SUCCESS(rv, objAttributeSet);
781 :
782 0 : AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
783 0 : objAttr->name = g_strdup(name.get());
784 0 : objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
785 0 : objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
786 : }
787 :
788 : //libspi will free it
789 0 : return objAttributeSet;
790 : }
791 :
792 : AtkAttributeSet*
793 0 : GetAttributeSet(nsAccessible* aAccessible)
794 : {
795 0 : nsCOMPtr<nsIPersistentProperties> attributes;
796 0 : aAccessible->GetAttributes(getter_AddRefs(attributes));
797 :
798 0 : if (attributes) {
799 : // Deal with attributes that we only need to expose in ATK
800 0 : if (aAccessible->State() & states::HASPOPUP) {
801 : // There is no ATK state for haspopup, must use object attribute to expose the same info
802 0 : nsAutoString oldValueUnused;
803 0 : attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"), NS_LITERAL_STRING("true"),
804 0 : oldValueUnused);
805 : }
806 :
807 0 : return ConvertToAtkAttributeSet(attributes);
808 : }
809 :
810 0 : return nsnull;
811 : }
812 :
813 : AtkAttributeSet *
814 0 : getAttributesCB(AtkObject *aAtkObj)
815 : {
816 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
817 :
818 0 : return accWrap ? GetAttributeSet(accWrap) : nsnull;
819 : }
820 :
821 : AtkObject *
822 0 : getParentCB(AtkObject *aAtkObj)
823 : {
824 0 : if (!aAtkObj->accessible_parent) {
825 0 : nsAccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj);
826 0 : if (!accWrap)
827 0 : return nsnull;
828 :
829 0 : nsAccessible* accParent = accWrap->Parent();
830 0 : if (!accParent)
831 0 : return nsnull;
832 :
833 0 : AtkObject* parent = nsAccessibleWrap::GetAtkObject(accParent);
834 0 : if (parent)
835 0 : atk_object_set_parent(aAtkObj, parent);
836 : }
837 0 : return aAtkObj->accessible_parent;
838 : }
839 :
840 : gint
841 0 : getChildCountCB(AtkObject *aAtkObj)
842 : {
843 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
844 0 : if (!accWrap || nsAccUtils::MustPrune(accWrap)) {
845 0 : return 0;
846 : }
847 :
848 0 : return accWrap->GetEmbeddedChildCount();
849 : }
850 :
851 : AtkObject *
852 0 : refChildCB(AtkObject *aAtkObj, gint aChildIndex)
853 : {
854 : // aChildIndex should not be less than zero
855 0 : if (aChildIndex < 0) {
856 0 : return nsnull;
857 : }
858 :
859 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
860 0 : if (!accWrap || nsAccUtils::MustPrune(accWrap)) {
861 0 : return nsnull;
862 : }
863 :
864 0 : nsAccessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex);
865 0 : if (!accChild)
866 0 : return nsnull;
867 :
868 0 : AtkObject* childAtkObj = nsAccessibleWrap::GetAtkObject(accChild);
869 :
870 0 : NS_ASSERTION(childAtkObj, "Fail to get AtkObj");
871 0 : if (!childAtkObj)
872 0 : return nsnull;
873 0 : g_object_ref(childAtkObj);
874 :
875 0 : if (aAtkObj != childAtkObj->accessible_parent)
876 0 : atk_object_set_parent(childAtkObj, aAtkObj);
877 :
878 0 : return childAtkObj;
879 : }
880 :
881 : gint
882 0 : getIndexInParentCB(AtkObject *aAtkObj)
883 : {
884 : // We don't use nsIAccessible::GetIndexInParent() because
885 : // for ATK we don't want to include text leaf nodes as children
886 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
887 0 : if (!accWrap) {
888 0 : return -1;
889 : }
890 :
891 0 : nsAccessible* parent = accWrap->Parent();
892 0 : if (!parent)
893 0 : return -1; // No parent
894 :
895 0 : return parent->GetIndexOfEmbeddedChild(accWrap);
896 : }
897 :
898 : static void
899 0 : TranslateStates(PRUint64 aState, AtkStateSet* aStateSet)
900 : {
901 :
902 : // Convert every state to an entry in AtkStateMap
903 0 : PRUint32 stateIndex = 0;
904 0 : PRUint64 bitMask = 1;
905 0 : while (gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState) {
906 0 : if (gAtkStateMap[stateIndex].atkState) { // There's potentially an ATK state for this
907 0 : bool isStateOn = (aState & bitMask) != 0;
908 0 : if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite) {
909 0 : isStateOn = !isStateOn;
910 : }
911 0 : if (isStateOn) {
912 0 : atk_state_set_add_state(aStateSet, gAtkStateMap[stateIndex].atkState);
913 : }
914 : }
915 0 : bitMask <<= 1;
916 0 : ++ stateIndex;
917 : }
918 0 : }
919 :
920 : AtkStateSet *
921 0 : refStateSetCB(AtkObject *aAtkObj)
922 : {
923 0 : AtkStateSet *state_set = nsnull;
924 0 : state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj);
925 :
926 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
927 0 : if (!accWrap) {
928 0 : TranslateStates(states::DEFUNCT, state_set);
929 0 : return state_set;
930 : }
931 :
932 : // Map states
933 0 : TranslateStates(accWrap->State(), state_set);
934 :
935 0 : return state_set;
936 : }
937 :
938 : AtkRelationSet *
939 0 : refRelationSetCB(AtkObject *aAtkObj)
940 : {
941 : AtkRelationSet* relation_set =
942 0 : ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
943 :
944 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
945 0 : if (!accWrap)
946 0 : return relation_set;
947 :
948 : PRUint32 relationTypes[] = {
949 : nsIAccessibleRelation::RELATION_LABELLED_BY,
950 : nsIAccessibleRelation::RELATION_LABEL_FOR,
951 : nsIAccessibleRelation::RELATION_NODE_CHILD_OF,
952 : nsIAccessibleRelation::RELATION_CONTROLLED_BY,
953 : nsIAccessibleRelation::RELATION_CONTROLLER_FOR,
954 : nsIAccessibleRelation::RELATION_EMBEDS,
955 : nsIAccessibleRelation::RELATION_FLOWS_TO,
956 : nsIAccessibleRelation::RELATION_FLOWS_FROM,
957 : nsIAccessibleRelation::RELATION_DESCRIBED_BY,
958 : nsIAccessibleRelation::RELATION_DESCRIPTION_FOR,
959 0 : };
960 :
961 0 : for (PRUint32 i = 0; i < ArrayLength(relationTypes); i++) {
962 0 : AtkRelationType atkType = static_cast<AtkRelationType>(relationTypes[i]);
963 : AtkRelation* atkRelation =
964 0 : atk_relation_set_get_relation_by_type(relation_set, atkType);
965 0 : if (atkRelation)
966 0 : atk_relation_set_remove(relation_set, atkRelation);
967 :
968 0 : Relation rel(accWrap->RelationByType(relationTypes[i]));
969 0 : nsTArray<AtkObject*> targets;
970 0 : nsAccessible* tempAcc = nsnull;
971 0 : while ((tempAcc = rel.Next()))
972 0 : targets.AppendElement(nsAccessibleWrap::GetAtkObject(tempAcc));
973 :
974 0 : if (targets.Length()) {
975 0 : atkRelation = atk_relation_new(targets.Elements(), targets.Length(), atkType);
976 0 : atk_relation_set_add(relation_set, atkRelation);
977 0 : g_object_unref(atkRelation);
978 : }
979 : }
980 :
981 0 : return relation_set;
982 : }
983 :
984 : // Check if aAtkObj is a valid MaiAtkObject, and return the nsAccessibleWrap
985 : // for it.
986 0 : nsAccessibleWrap *GetAccessibleWrap(AtkObject *aAtkObj)
987 : {
988 0 : NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nsnull);
989 0 : nsAccessibleWrap *tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
990 :
991 : // Check if AccessibleWrap was deconstructed
992 0 : if (tmpAccWrap == nsnull) {
993 0 : return nsnull;
994 : }
995 :
996 0 : NS_ENSURE_TRUE(tmpAccWrap->GetAtkObject() == aAtkObj, nsnull);
997 :
998 : nsApplicationAccessible *applicationAcc =
999 0 : nsAccessNode::GetApplicationAccessible();
1000 : nsAccessibleWrap* tmpAppAccWrap =
1001 0 : static_cast<nsAccessibleWrap*>(applicationAcc);
1002 :
1003 0 : if (tmpAppAccWrap != tmpAccWrap && !tmpAccWrap->IsValidObject())
1004 0 : return nsnull;
1005 :
1006 0 : return tmpAccWrap;
1007 : }
1008 :
1009 : nsresult
1010 0 : nsAccessibleWrap::HandleAccEvent(AccEvent* aEvent)
1011 : {
1012 0 : nsresult rv = nsAccessible::HandleAccEvent(aEvent);
1013 0 : NS_ENSURE_SUCCESS(rv, rv);
1014 :
1015 0 : return FirePlatformEvent(aEvent);
1016 : }
1017 :
1018 : nsresult
1019 0 : nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
1020 : {
1021 0 : nsAccessible *accessible = aEvent->GetAccessible();
1022 0 : NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
1023 :
1024 0 : PRUint32 type = aEvent->GetEventType();
1025 :
1026 0 : AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);
1027 :
1028 : // We don't create ATK objects for nsIAccessible plain text leaves,
1029 : // just return NS_OK in such case
1030 0 : if (!atkObj) {
1031 0 : NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW ||
1032 : type == nsIAccessibleEvent::EVENT_HIDE,
1033 : "Event other than SHOW and HIDE fired for plain text leaves");
1034 0 : return NS_OK;
1035 : }
1036 :
1037 0 : nsAccessibleWrap *accWrap = GetAccessibleWrap(atkObj);
1038 0 : if (!accWrap) {
1039 0 : return NS_OK; // Node is shut down
1040 : }
1041 :
1042 0 : switch (type) {
1043 : case nsIAccessibleEvent::EVENT_STATE_CHANGE:
1044 0 : return FireAtkStateChangeEvent(aEvent, atkObj);
1045 :
1046 : case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
1047 : case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
1048 0 : return FireAtkTextChangedEvent(aEvent, atkObj);
1049 :
1050 : case nsIAccessibleEvent::EVENT_FOCUS:
1051 : {
1052 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n"));
1053 0 : nsRootAccessible* rootAccWrap = accWrap->RootAccessible();
1054 0 : if (rootAccWrap && rootAccWrap->mActivated) {
1055 0 : atk_focus_tracker_notify(atkObj);
1056 : // Fire state change event for focus
1057 : nsRefPtr<AccEvent> stateChangeEvent =
1058 0 : new AccStateChangeEvent(accessible, states::FOCUSED, true);
1059 0 : return FireAtkStateChangeEvent(stateChangeEvent, atkObj);
1060 : }
1061 0 : } break;
1062 :
1063 : case nsIAccessibleEvent::EVENT_NAME_CHANGE:
1064 : {
1065 0 : nsString newName;
1066 0 : accessible->GetName(newName);
1067 0 : NS_ConvertUTF16toUTF8 utf8Name(newName);
1068 0 : if (!atkObj->name || !utf8Name.Equals(atkObj->name))
1069 0 : atk_object_set_name(atkObj, utf8Name.get());
1070 :
1071 : break;
1072 : }
1073 : case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
1074 : {
1075 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_VALUE_CHANGE\n"));
1076 0 : nsCOMPtr<nsIAccessibleValue> value(do_QueryObject(accessible));
1077 0 : if (value) { // Make sure this is a numeric value
1078 : // Don't fire for MSAA string value changes (e.g. text editing)
1079 : // ATK values are always numeric
1080 0 : g_object_notify( (GObject*)atkObj, "accessible-value" );
1081 : }
1082 0 : } break;
1083 :
1084 : case nsIAccessibleEvent::EVENT_SELECTION:
1085 : case nsIAccessibleEvent::EVENT_SELECTION_ADD:
1086 : case nsIAccessibleEvent::EVENT_SELECTION_REMOVE:
1087 : {
1088 : // XXX: dupe events may be fired
1089 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n"));
1090 0 : AccSelChangeEvent* selChangeEvent = downcast_accEvent(aEvent);
1091 0 : g_signal_emit_by_name(nsAccessibleWrap::GetAtkObject(selChangeEvent->Widget()),
1092 0 : "selection_changed");
1093 0 : break;
1094 : }
1095 :
1096 : case nsIAccessibleEvent::EVENT_SELECTION_WITHIN:
1097 : {
1098 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n"));
1099 0 : g_signal_emit_by_name(atkObj, "selection_changed");
1100 0 : break;
1101 : }
1102 :
1103 : case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
1104 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_SELECTION_CHANGED\n"));
1105 0 : g_signal_emit_by_name(atkObj, "text_selection_changed");
1106 0 : break;
1107 :
1108 : case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
1109 : {
1110 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_CARET_MOVED\n"));
1111 :
1112 0 : AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent);
1113 0 : NS_ASSERTION(caretMoveEvent, "Event needs event data");
1114 0 : if (!caretMoveEvent)
1115 0 : break;
1116 :
1117 0 : PRInt32 caretOffset = caretMoveEvent->GetCaretOffset();
1118 :
1119 0 : MAI_LOG_DEBUG(("\n\nCaret postion: %d", caretOffset));
1120 : g_signal_emit_by_name(atkObj,
1121 : "text_caret_moved",
1122 : // Curent caret position
1123 0 : caretOffset);
1124 0 : } break;
1125 :
1126 : case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED:
1127 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_ATTRIBUTE_CHANGED\n"));
1128 :
1129 : g_signal_emit_by_name(atkObj,
1130 0 : "text-attributes-changed");
1131 0 : break;
1132 :
1133 : case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED:
1134 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_MODEL_CHANGED\n"));
1135 0 : g_signal_emit_by_name(atkObj, "model_changed");
1136 0 : break;
1137 :
1138 : case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT:
1139 : {
1140 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_INSERT\n"));
1141 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1142 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1143 :
1144 0 : PRInt32 rowIndex = tableEvent->GetIndex();
1145 0 : PRInt32 numRows = tableEvent->GetCount();
1146 :
1147 : g_signal_emit_by_name(atkObj,
1148 : "row_inserted",
1149 : // After which the rows are inserted
1150 : rowIndex,
1151 : // The number of the inserted
1152 0 : numRows);
1153 0 : } break;
1154 :
1155 : case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE:
1156 : {
1157 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_DELETE\n"));
1158 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1159 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1160 :
1161 0 : PRInt32 rowIndex = tableEvent->GetIndex();
1162 0 : PRInt32 numRows = tableEvent->GetCount();
1163 :
1164 : g_signal_emit_by_name(atkObj,
1165 : "row_deleted",
1166 : // After which the rows are deleted
1167 : rowIndex,
1168 : // The number of the deleted
1169 0 : numRows);
1170 0 : } break;
1171 :
1172 : case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER:
1173 : {
1174 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_REORDER\n"));
1175 0 : g_signal_emit_by_name(atkObj, "row_reordered");
1176 0 : break;
1177 : }
1178 :
1179 : case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT:
1180 : {
1181 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_INSERT\n"));
1182 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1183 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1184 :
1185 0 : PRInt32 colIndex = tableEvent->GetIndex();
1186 0 : PRInt32 numCols = tableEvent->GetCount();
1187 :
1188 : g_signal_emit_by_name(atkObj,
1189 : "column_inserted",
1190 : // After which the columns are inserted
1191 : colIndex,
1192 : // The number of the inserted
1193 0 : numCols);
1194 0 : } break;
1195 :
1196 : case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE:
1197 : {
1198 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_DELETE\n"));
1199 0 : AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1200 0 : NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1201 :
1202 0 : PRInt32 colIndex = tableEvent->GetIndex();
1203 0 : PRInt32 numCols = tableEvent->GetCount();
1204 :
1205 : g_signal_emit_by_name(atkObj,
1206 : "column_deleted",
1207 : // After which the columns are deleted
1208 : colIndex,
1209 : // The number of the deleted
1210 0 : numCols);
1211 0 : } break;
1212 :
1213 : case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER:
1214 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_REORDER\n"));
1215 0 : g_signal_emit_by_name(atkObj, "column_reordered");
1216 0 : break;
1217 :
1218 : case nsIAccessibleEvent::EVENT_SECTION_CHANGED:
1219 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_SECTION_CHANGED\n"));
1220 0 : g_signal_emit_by_name(atkObj, "visible_data_changed");
1221 0 : break;
1222 :
1223 : case nsIAccessibleEvent::EVENT_SHOW:
1224 0 : return FireAtkShowHideEvent(aEvent, atkObj, true);
1225 :
1226 : case nsIAccessibleEvent::EVENT_HIDE:
1227 0 : return FireAtkShowHideEvent(aEvent, atkObj, false);
1228 :
1229 : /*
1230 : * Because dealing with menu is very different between nsIAccessible
1231 : * and ATK, and the menu activity is important, specially transfer the
1232 : * following two event.
1233 : * Need more verification by AT test.
1234 : */
1235 : case nsIAccessibleEvent::EVENT_MENU_START:
1236 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENU_START\n"));
1237 0 : break;
1238 :
1239 : case nsIAccessibleEvent::EVENT_MENU_END:
1240 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENU_END\n"));
1241 0 : break;
1242 :
1243 : case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE:
1244 : {
1245 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_ACTIVATED\n"));
1246 : nsRootAccessible *rootAcc =
1247 0 : static_cast<nsRootAccessible *>(accessible);
1248 0 : rootAcc->mActivated = true;
1249 0 : guint id = g_signal_lookup ("activate", MAI_TYPE_ATK_OBJECT);
1250 0 : g_signal_emit(atkObj, id, 0);
1251 :
1252 : // Always fire a current focus event after activation.
1253 0 : FocusMgr()->ForceFocusEvent();
1254 0 : } break;
1255 :
1256 : case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE:
1257 : {
1258 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_DEACTIVATED\n"));
1259 : nsRootAccessible *rootAcc =
1260 0 : static_cast<nsRootAccessible *>(accessible);
1261 0 : rootAcc->mActivated = false;
1262 0 : guint id = g_signal_lookup ("deactivate", MAI_TYPE_ATK_OBJECT);
1263 0 : g_signal_emit(atkObj, id, 0);
1264 0 : } break;
1265 :
1266 : case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE:
1267 : {
1268 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_MAXIMIZE\n"));
1269 0 : guint id = g_signal_lookup ("maximize", MAI_TYPE_ATK_OBJECT);
1270 0 : g_signal_emit(atkObj, id, 0);
1271 0 : } break;
1272 :
1273 : case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE:
1274 : {
1275 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_MINIMIZE\n"));
1276 0 : guint id = g_signal_lookup ("minimize", MAI_TYPE_ATK_OBJECT);
1277 0 : g_signal_emit(atkObj, id, 0);
1278 0 : } break;
1279 :
1280 : case nsIAccessibleEvent::EVENT_WINDOW_RESTORE:
1281 : {
1282 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_RESTORE\n"));
1283 0 : guint id = g_signal_lookup ("restore", MAI_TYPE_ATK_OBJECT);
1284 0 : g_signal_emit(atkObj, id, 0);
1285 0 : } break;
1286 :
1287 : case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
1288 : {
1289 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_COMPLETE\n"));
1290 0 : g_signal_emit_by_name (atkObj, "load_complete");
1291 0 : } break;
1292 :
1293 : case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD:
1294 : {
1295 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_RELOAD\n"));
1296 0 : g_signal_emit_by_name (atkObj, "reload");
1297 0 : } break;
1298 :
1299 : case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED:
1300 : {
1301 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_STOPPED\n"));
1302 0 : g_signal_emit_by_name (atkObj, "load_stopped");
1303 0 : } break;
1304 :
1305 : case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
1306 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUPOPUP_START\n"));
1307 0 : atk_focus_tracker_notify(atkObj); // fire extra focus event
1308 0 : atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, true);
1309 0 : atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, true);
1310 0 : break;
1311 :
1312 : case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
1313 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUPOPUP_END\n"));
1314 0 : atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, false);
1315 0 : atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, false);
1316 0 : break;
1317 : }
1318 :
1319 0 : return NS_OK;
1320 : }
1321 :
1322 : nsresult
1323 0 : nsAccessibleWrap::FireAtkStateChangeEvent(AccEvent* aEvent,
1324 : AtkObject *aObject)
1325 : {
1326 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_STATE_CHANGE\n"));
1327 :
1328 0 : AccStateChangeEvent* event = downcast_accEvent(aEvent);
1329 0 : NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
1330 :
1331 0 : bool isEnabled = event->IsStateEnabled();
1332 0 : PRInt32 stateIndex = AtkStateMap::GetStateIndexFor(event->GetState());
1333 0 : if (stateIndex >= 0) {
1334 0 : NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoSuchState,
1335 : "No such state");
1336 :
1337 0 : if (gAtkStateMap[stateIndex].atkState != kNone) {
1338 0 : NS_ASSERTION(gAtkStateMap[stateIndex].stateMapEntryType != kNoStateChange,
1339 : "State changes should not fired for this state");
1340 :
1341 0 : if (gAtkStateMap[stateIndex].stateMapEntryType == kMapOpposite)
1342 0 : isEnabled = !isEnabled;
1343 :
1344 : // Fire state change for first state if there is one to map
1345 : atk_object_notify_state_change(aObject,
1346 : gAtkStateMap[stateIndex].atkState,
1347 0 : isEnabled);
1348 : }
1349 : }
1350 :
1351 0 : return NS_OK;
1352 : }
1353 :
1354 : nsresult
1355 0 : nsAccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
1356 : AtkObject *aObject)
1357 : {
1358 0 : MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));
1359 :
1360 0 : AccTextChangeEvent* event = downcast_accEvent(aEvent);
1361 0 : NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
1362 :
1363 0 : PRInt32 start = event->GetStartOffset();
1364 0 : PRUint32 length = event->GetLength();
1365 0 : bool isInserted = event->IsTextInserted();
1366 0 : bool isFromUserInput = aEvent->IsFromUserInput();
1367 0 : char* signal_name = nsnull;
1368 :
1369 0 : if (gAvailableAtkSignals == eUnknown)
1370 : gAvailableAtkSignals =
1371 0 : g_signal_lookup("text-insert", G_OBJECT_TYPE(aObject)) ?
1372 0 : eHaveNewAtkTextSignals : eNoNewAtkSignals;
1373 :
1374 0 : if (gAvailableAtkSignals == eNoNewAtkSignals) {
1375 : // XXX remove this code and the gHaveNewTextSignals check when we can
1376 : // stop supporting old atk since it doesn't really work anyway
1377 : // see bug 619002
1378 : signal_name = g_strconcat(isInserted ? "text_changed::insert" :
1379 : "text_changed::delete",
1380 0 : isFromUserInput ? "" : kNonUserInputEvent, NULL);
1381 0 : g_signal_emit_by_name(aObject, signal_name, start, length);
1382 : } else {
1383 0 : nsAutoString text;
1384 0 : event->GetModifiedText(text);
1385 : signal_name = g_strconcat(isInserted ? "text-insert" : "text-remove",
1386 0 : isFromUserInput ? "" : "::system", NULL);
1387 : g_signal_emit_by_name(aObject, signal_name, start, length,
1388 0 : NS_ConvertUTF16toUTF8(text).get());
1389 : }
1390 :
1391 0 : g_free(signal_name);
1392 0 : return NS_OK;
1393 : }
1394 :
1395 : nsresult
1396 0 : nsAccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent,
1397 : AtkObject *aObject, bool aIsAdded)
1398 : {
1399 0 : if (aIsAdded)
1400 0 : MAI_LOG_DEBUG(("\n\nReceived: Show event\n"));
1401 : else
1402 0 : MAI_LOG_DEBUG(("\n\nReceived: Hide event\n"));
1403 :
1404 0 : PRInt32 indexInParent = getIndexInParentCB(aObject);
1405 0 : AtkObject *parentObject = getParentCB(aObject);
1406 0 : NS_ENSURE_STATE(parentObject);
1407 :
1408 0 : bool isFromUserInput = aEvent->IsFromUserInput();
1409 : char *signal_name = g_strconcat(aIsAdded ? "children_changed::add" : "children_changed::remove",
1410 0 : isFromUserInput ? "" : kNonUserInputEvent, NULL);
1411 0 : g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, NULL);
1412 0 : g_free(signal_name);
1413 :
1414 0 : return NS_OK;
1415 : }
1416 :
|