Bug 589145 - dexpcom accessible event classes, r=davidb, sr=neil, a=davidb
[mozilla-central.git] / accessible / src / atk / nsAccessibleWrap.cpp
blob0ec83cdeaad253a405dab764fd1edeb226c154aa
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
3 */
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is mozilla.org code.
19 * The Initial Developer of the Original Code is
20 * Sun Microsystems, Inc.
21 * Portions created by the Initial Developer are Copyright (C) 2002
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Bolian Yin (bolian.yin@sun.com)
26 * John Sun (john.sun@sun.com)
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "nsAccessibleWrap.h"
44 #include "nsAccUtils.h"
45 #include "nsApplicationAccessibleWrap.h"
46 #include "nsRootAccessible.h"
47 #include "nsDocAccessibleWrap.h"
48 #include "nsIAccessibleValue.h"
49 #include "nsString.h"
50 #include "nsAutoPtr.h"
51 #include "prprf.h"
52 #include "nsRoleMap.h"
53 #include "nsRelUtils.h"
54 #include "nsStateMap.h"
56 #include "nsMaiInterfaceComponent.h"
57 #include "nsMaiInterfaceAction.h"
58 #include "nsMaiInterfaceText.h"
59 #include "nsMaiInterfaceEditableText.h"
60 #include "nsMaiInterfaceSelection.h"
61 #include "nsMaiInterfaceValue.h"
62 #include "nsMaiInterfaceHypertext.h"
63 #include "nsMaiInterfaceHyperlinkImpl.h"
64 #include "nsMaiInterfaceTable.h"
65 #include "nsXPCOMStrings.h"
66 #include "nsComponentManagerUtils.h"
67 #include "nsMaiInterfaceDocument.h"
68 #include "nsMaiInterfaceImage.h"
70 //defined in nsApplicationAccessibleWrap.cpp
71 extern "C" GType g_atk_hyperlink_impl_type;
73 /* MaiAtkObject */
75 enum {
76 ACTIVATE,
77 CREATE,
78 DEACTIVATE,
79 DESTROY,
80 MAXIMIZE,
81 MINIMIZE,
82 RESIZE,
83 RESTORE,
84 LAST_SIGNAL
87 enum MaiInterfaceType {
88 MAI_INTERFACE_COMPONENT, /* 0 */
89 MAI_INTERFACE_ACTION,
90 MAI_INTERFACE_VALUE,
91 MAI_INTERFACE_EDITABLE_TEXT,
92 MAI_INTERFACE_HYPERTEXT,
93 MAI_INTERFACE_HYPERLINK_IMPL,
94 MAI_INTERFACE_SELECTION,
95 MAI_INTERFACE_TABLE,
96 MAI_INTERFACE_TEXT,
97 MAI_INTERFACE_DOCUMENT,
98 MAI_INTERFACE_IMAGE /* 10 */
101 static GType GetAtkTypeForMai(MaiInterfaceType type)
103 switch (type) {
104 case MAI_INTERFACE_COMPONENT:
105 return ATK_TYPE_COMPONENT;
106 case MAI_INTERFACE_ACTION:
107 return ATK_TYPE_ACTION;
108 case MAI_INTERFACE_VALUE:
109 return ATK_TYPE_VALUE;
110 case MAI_INTERFACE_EDITABLE_TEXT:
111 return ATK_TYPE_EDITABLE_TEXT;
112 case MAI_INTERFACE_HYPERTEXT:
113 return ATK_TYPE_HYPERTEXT;
114 case MAI_INTERFACE_HYPERLINK_IMPL:
115 return g_atk_hyperlink_impl_type;
116 case MAI_INTERFACE_SELECTION:
117 return ATK_TYPE_SELECTION;
118 case MAI_INTERFACE_TABLE:
119 return ATK_TYPE_TABLE;
120 case MAI_INTERFACE_TEXT:
121 return ATK_TYPE_TEXT;
122 case MAI_INTERFACE_DOCUMENT:
123 return ATK_TYPE_DOCUMENT;
124 case MAI_INTERFACE_IMAGE:
125 return ATK_TYPE_IMAGE;
127 return G_TYPE_INVALID;
130 static const char* kNonUserInputEvent = ":system";
132 static const GInterfaceInfo atk_if_infos[] = {
133 {(GInterfaceInitFunc)componentInterfaceInitCB,
134 (GInterfaceFinalizeFunc) NULL, NULL},
135 {(GInterfaceInitFunc)actionInterfaceInitCB,
136 (GInterfaceFinalizeFunc) NULL, NULL},
137 {(GInterfaceInitFunc)valueInterfaceInitCB,
138 (GInterfaceFinalizeFunc) NULL, NULL},
139 {(GInterfaceInitFunc)editableTextInterfaceInitCB,
140 (GInterfaceFinalizeFunc) NULL, NULL},
141 {(GInterfaceInitFunc)hypertextInterfaceInitCB,
142 (GInterfaceFinalizeFunc) NULL, NULL},
143 {(GInterfaceInitFunc)hyperlinkImplInterfaceInitCB,
144 (GInterfaceFinalizeFunc) NULL, NULL},
145 {(GInterfaceInitFunc)selectionInterfaceInitCB,
146 (GInterfaceFinalizeFunc) NULL, NULL},
147 {(GInterfaceInitFunc)tableInterfaceInitCB,
148 (GInterfaceFinalizeFunc) NULL, NULL},
149 {(GInterfaceInitFunc)textInterfaceInitCB,
150 (GInterfaceFinalizeFunc) NULL, NULL},
151 {(GInterfaceInitFunc)documentInterfaceInitCB,
152 (GInterfaceFinalizeFunc) NULL, NULL},
153 {(GInterfaceInitFunc)imageInterfaceInitCB,
154 (GInterfaceFinalizeFunc) NULL, NULL}
158 * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject
160 struct MaiAtkObject
162 AtkObject parent;
164 * The nsAccessibleWrap whose properties and features are exported
165 * via this object instance.
167 nsAccessibleWrap *accWrap;
170 struct MaiAtkObjectClass
172 AtkObjectClass parent_class;
175 static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
177 #ifdef MAI_LOGGING
178 PRInt32 sMaiAtkObjCreated = 0;
179 PRInt32 sMaiAtkObjDeleted = 0;
180 #endif
182 G_BEGIN_DECLS
183 /* callbacks for MaiAtkObject */
184 static void classInitCB(AtkObjectClass *aClass);
185 static void initializeCB(AtkObject *aAtkObj, gpointer aData);
186 static void finalizeCB(GObject *aObj);
188 /* callbacks for AtkObject virtual functions */
189 static const gchar* getNameCB (AtkObject *aAtkObj);
190 /* getDescriptionCB is also used by image interface */
191 const gchar* getDescriptionCB (AtkObject *aAtkObj);
192 static AtkRole getRoleCB(AtkObject *aAtkObj);
193 static AtkAttributeSet* getAttributesCB(AtkObject *aAtkObj);
194 static AtkObject* getParentCB(AtkObject *aAtkObj);
195 static gint getChildCountCB(AtkObject *aAtkObj);
196 static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex);
197 static gint getIndexInParentCB(AtkObject *aAtkObj);
198 static AtkStateSet* refStateSetCB(AtkObject *aAtkObj);
199 static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj);
201 /* the missing atkobject virtual functions */
203 static AtkLayer getLayerCB(AtkObject *aAtkObj);
204 static gint getMdiZorderCB(AtkObject *aAtkObj);
205 static void SetNameCB(AtkObject *aAtkObj,
206 const gchar *name);
207 static void SetDescriptionCB(AtkObject *aAtkObj,
208 const gchar *description);
209 static void SetParentCB(AtkObject *aAtkObj,
210 AtkObject *parent);
211 static void SetRoleCB(AtkObject *aAtkObj,
212 AtkRole role);
213 static guint ConnectPropertyChangeHandlerCB(
214 AtkObject *aObj,
215 AtkPropertyChangeHandler *handler);
216 static void RemovePropertyChangeHandlerCB(
217 AtkObject *aAtkObj,
218 guint handler_id);
219 static void InitializeCB(AtkObject *aAtkObj,
220 gpointer data);
221 static void ChildrenChangedCB(AtkObject *aAtkObj,
222 guint change_index,
223 gpointer changed_child);
224 static void FocusEventCB(AtkObject *aAtkObj,
225 gboolean focus_in);
226 static void PropertyChangeCB(AtkObject *aAtkObj,
227 AtkPropertyValues *values);
228 static void StateChangeCB(AtkObject *aAtkObj,
229 const gchar *name,
230 gboolean state_set);
231 static void VisibleDataChangedCB(AtkObject *aAtkObj);
233 G_END_DECLS
235 static GType GetMaiAtkType(PRUint16 interfacesBits);
236 static const char * GetUniqueMaiAtkTypeName(PRUint16 interfacesBits);
238 static gpointer parent_class = NULL;
240 static GQuark quark_mai_hyperlink = 0;
242 GType
243 mai_atk_object_get_type(void)
245 static GType type = 0;
247 if (!type) {
248 static const GTypeInfo tinfo = {
249 sizeof(MaiAtkObjectClass),
250 (GBaseInitFunc)NULL,
251 (GBaseFinalizeFunc)NULL,
252 (GClassInitFunc)classInitCB,
253 (GClassFinalizeFunc)NULL,
254 NULL, /* class data */
255 sizeof(MaiAtkObject), /* instance size */
256 0, /* nb preallocs */
257 (GInstanceInitFunc)NULL,
258 NULL /* value table */
261 type = g_type_register_static(ATK_TYPE_OBJECT,
262 "MaiAtkObject", &tinfo, GTypeFlags(0));
263 quark_mai_hyperlink = g_quark_from_static_string("MaiHyperlink");
265 return type;
268 #ifdef MAI_LOGGING
269 PRInt32 nsAccessibleWrap::mAccWrapCreated = 0;
270 PRInt32 nsAccessibleWrap::mAccWrapDeleted = 0;
271 #endif
273 nsAccessibleWrap::
274 nsAccessibleWrap(nsIContent *aContent, nsIWeakReference *aShell) :
275 nsAccessible(aContent, aShell), mAtkObject(nsnull)
277 #ifdef MAI_LOGGING
278 ++mAccWrapCreated;
279 #endif
280 MAI_LOG_DEBUG(("==nsAccessibleWrap creating: this=%p,total=%d left=%d\n",
281 (void*)this, mAccWrapCreated,
282 (mAccWrapCreated-mAccWrapDeleted)));
285 nsAccessibleWrap::~nsAccessibleWrap()
287 NS_ASSERTION(!mAtkObject, "ShutdownAtkObject() is not called");
289 #ifdef MAI_LOGGING
290 ++mAccWrapDeleted;
291 #endif
292 MAI_LOG_DEBUG(("==nsAccessibleWrap deleting: this=%p,total=%d left=%d\n",
293 (void*)this, mAccWrapDeleted,
294 (mAccWrapCreated-mAccWrapDeleted)));
297 void nsAccessibleWrap::ShutdownAtkObject()
299 if (mAtkObject) {
300 if (IS_MAI_OBJECT(mAtkObject)) {
301 MAI_ATK_OBJECT(mAtkObject)->accWrap = nsnull;
303 SetMaiHyperlink(nsnull);
304 g_object_unref(mAtkObject);
305 mAtkObject = nsnull;
309 void
310 nsAccessibleWrap::Shutdown()
312 ShutdownAtkObject();
313 nsAccessible::Shutdown();
316 MaiHyperlink* nsAccessibleWrap::GetMaiHyperlink(PRBool aCreate /* = PR_TRUE */)
318 // make sure mAtkObject is created
319 GetAtkObject();
321 NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
322 NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject");
323 MaiHyperlink* maiHyperlink = nsnull;
324 if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) {
325 maiHyperlink = (MaiHyperlink*)g_object_get_qdata(G_OBJECT(mAtkObject),
326 quark_mai_hyperlink);
327 if (!maiHyperlink && aCreate) {
328 maiHyperlink = new MaiHyperlink(this);
329 SetMaiHyperlink(maiHyperlink);
332 return maiHyperlink;
335 void nsAccessibleWrap::SetMaiHyperlink(MaiHyperlink* aMaiHyperlink)
337 NS_ASSERTION(quark_mai_hyperlink, "quark_mai_hyperlink not initialized");
338 NS_ASSERTION(IS_MAI_OBJECT(mAtkObject), "Invalid AtkObject");
339 if (quark_mai_hyperlink && IS_MAI_OBJECT(mAtkObject)) {
340 MaiHyperlink* maiHyperlink = GetMaiHyperlink(PR_FALSE);
341 if (!maiHyperlink && !aMaiHyperlink) {
342 return; // Never set and we're shutting down
344 if (maiHyperlink) {
345 delete maiHyperlink;
347 g_object_set_qdata(G_OBJECT(mAtkObject), quark_mai_hyperlink,
348 aMaiHyperlink);
352 NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible)
354 *aOutAccessible = nsnull;
356 if (!mAtkObject) {
357 if (!mWeakShell || !nsAccUtils::IsEmbeddedObject(this)) {
358 // We don't create ATK objects for node which has been shutdown, or
359 // nsIAccessible plain text leaves
360 return NS_ERROR_FAILURE;
363 GType type = GetMaiAtkType(CreateMaiInterfaces());
364 NS_ENSURE_TRUE(type, NS_ERROR_FAILURE);
365 mAtkObject =
366 reinterpret_cast<AtkObject *>
367 (g_object_new(type, NULL));
368 NS_ENSURE_TRUE(mAtkObject, NS_ERROR_OUT_OF_MEMORY);
370 atk_object_initialize(mAtkObject, this);
371 mAtkObject->role = ATK_ROLE_INVALID;
372 mAtkObject->layer = ATK_LAYER_INVALID;
375 *aOutAccessible = mAtkObject;
376 return NS_OK;
379 AtkObject *
380 nsAccessibleWrap::GetAtkObject(void)
382 void *atkObj = nsnull;
383 GetNativeInterface(&atkObj);
384 return static_cast<AtkObject *>(atkObj);
387 // Get AtkObject from nsIAccessible interface
388 /* static */
389 AtkObject *
390 nsAccessibleWrap::GetAtkObject(nsIAccessible * acc)
392 void *atkObjPtr = nsnull;
393 acc->GetNativeInterface(&atkObjPtr);
394 return atkObjPtr ? ATK_OBJECT(atkObjPtr) : nsnull;
397 /* private */
398 PRUint16
399 nsAccessibleWrap::CreateMaiInterfaces(void)
401 PRUint16 interfacesBits = 0;
403 // Add Interfaces for each nsIAccessible.ext interfaces
405 // the Component interface are supported by all nsIAccessible
406 interfacesBits |= 1 << MAI_INTERFACE_COMPONENT;
408 // Add Action interface if the action count is more than zero.
409 PRUint8 actionCount = 0;
410 nsresult rv = GetNumActions(&actionCount);
411 if (NS_SUCCEEDED(rv) && actionCount > 0) {
412 interfacesBits |= 1 << MAI_INTERFACE_ACTION;
415 //nsIAccessibleText
416 nsCOMPtr<nsIAccessibleText> accessInterfaceText;
417 QueryInterface(NS_GET_IID(nsIAccessibleText),
418 getter_AddRefs(accessInterfaceText));
419 if (accessInterfaceText) {
420 interfacesBits |= 1 << MAI_INTERFACE_TEXT;
423 //nsIAccessibleEditableText
424 nsCOMPtr<nsIAccessibleEditableText> accessInterfaceEditableText;
425 QueryInterface(NS_GET_IID(nsIAccessibleEditableText),
426 getter_AddRefs(accessInterfaceEditableText));
427 if (accessInterfaceEditableText) {
428 interfacesBits |= 1 << MAI_INTERFACE_EDITABLE_TEXT;
431 //nsIAccessibleValue
432 nsCOMPtr<nsIAccessibleValue> accessInterfaceValue;
433 QueryInterface(NS_GET_IID(nsIAccessibleValue),
434 getter_AddRefs(accessInterfaceValue));
435 if (accessInterfaceValue) {
436 interfacesBits |= 1 << MAI_INTERFACE_VALUE;
439 //nsIAccessibleDocument
440 nsCOMPtr<nsIAccessibleDocument> accessInterfaceDocument;
441 QueryInterface(NS_GET_IID(nsIAccessibleDocument),
442 getter_AddRefs(accessInterfaceDocument));
443 if (accessInterfaceDocument) {
444 interfacesBits |= 1 << MAI_INTERFACE_DOCUMENT;
447 //nsIAccessibleImage
448 nsCOMPtr<nsIAccessibleImage> accessInterfaceImage;
449 QueryInterface(NS_GET_IID(nsIAccessibleImage),
450 getter_AddRefs(accessInterfaceImage));
451 if (accessInterfaceImage) {
452 interfacesBits |= 1 << MAI_INTERFACE_IMAGE;
455 //nsIAccessibleHyperLink
456 nsCOMPtr<nsIAccessibleHyperLink> accessInterfaceHyperlink;
457 QueryInterface(NS_GET_IID(nsIAccessibleHyperLink),
458 getter_AddRefs(accessInterfaceHyperlink));
459 if (accessInterfaceHyperlink) {
460 interfacesBits |= 1 << MAI_INTERFACE_HYPERLINK_IMPL;
463 if (!nsAccUtils::MustPrune(this)) { // These interfaces require children
464 //nsIAccessibleHypertext
465 nsCOMPtr<nsIAccessibleHyperText> accessInterfaceHypertext;
466 QueryInterface(NS_GET_IID(nsIAccessibleHyperText),
467 getter_AddRefs(accessInterfaceHypertext));
468 if (accessInterfaceHypertext) {
469 interfacesBits |= 1 << MAI_INTERFACE_HYPERTEXT;
472 //nsIAccessibleTable
473 nsCOMPtr<nsIAccessibleTable> accessInterfaceTable;
474 QueryInterface(NS_GET_IID(nsIAccessibleTable),
475 getter_AddRefs(accessInterfaceTable));
476 if (accessInterfaceTable) {
477 interfacesBits |= 1 << MAI_INTERFACE_TABLE;
480 //nsIAccessibleSelection
481 nsCOMPtr<nsIAccessibleSelectable> accessInterfaceSelection;
482 QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
483 getter_AddRefs(accessInterfaceSelection));
484 if (accessInterfaceSelection) {
485 interfacesBits |= 1 << MAI_INTERFACE_SELECTION;
489 return interfacesBits;
492 static GType
493 GetMaiAtkType(PRUint16 interfacesBits)
495 GType type;
496 static const GTypeInfo tinfo = {
497 sizeof(MaiAtkObjectClass),
498 (GBaseInitFunc) NULL,
499 (GBaseFinalizeFunc) NULL,
500 (GClassInitFunc) NULL,
501 (GClassFinalizeFunc) NULL,
502 NULL, /* class data */
503 sizeof(MaiAtkObject), /* instance size */
504 0, /* nb preallocs */
505 (GInstanceInitFunc) NULL,
506 NULL /* value table */
510 * The members we use to register GTypes are GetAtkTypeForMai
511 * and atk_if_infos, which are constant values to each MaiInterface
512 * So we can reuse the registered GType when having
513 * the same MaiInterface types.
515 const char *atkTypeName = GetUniqueMaiAtkTypeName(interfacesBits);
516 type = g_type_from_name(atkTypeName);
517 if (type) {
518 return type;
522 * gobject limits the number of types that can directly derive from any
523 * given object type to 4095.
525 static PRUint16 typeRegCount = 0;
526 if (typeRegCount++ >= 4095) {
527 return G_TYPE_INVALID;
529 type = g_type_register_static(MAI_TYPE_ATK_OBJECT,
530 atkTypeName,
531 &tinfo, GTypeFlags(0));
533 for (PRUint32 index = 0; index < NS_ARRAY_LENGTH(atk_if_infos); index++) {
534 if (interfacesBits & (1 << index)) {
535 g_type_add_interface_static(type,
536 GetAtkTypeForMai((MaiInterfaceType)index),
537 &atk_if_infos[index]);
541 return type;
544 static const char *
545 GetUniqueMaiAtkTypeName(PRUint16 interfacesBits)
547 #define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(PRUint16)*8/4+1 < 30 */
549 static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */
550 static gchar name[MAI_ATK_TYPE_NAME_LEN + 1];
552 PR_snprintf(name, MAI_ATK_TYPE_NAME_LEN, "%s%x", namePrefix,
553 interfacesBits);
554 name[MAI_ATK_TYPE_NAME_LEN] = '\0';
556 MAI_LOG_DEBUG(("MaiWidget::LastedTypeName=%s\n", name));
558 return name;
561 PRBool nsAccessibleWrap::IsValidObject()
563 // to ensure we are not shut down
564 return !IsDefunct();
567 /* static functions for ATK callbacks */
568 void
569 classInitCB(AtkObjectClass *aClass)
571 GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
573 parent_class = g_type_class_peek_parent(aClass);
575 aClass->get_name = getNameCB;
576 aClass->get_description = getDescriptionCB;
577 aClass->get_parent = getParentCB;
578 aClass->get_n_children = getChildCountCB;
579 aClass->ref_child = refChildCB;
580 aClass->get_index_in_parent = getIndexInParentCB;
581 aClass->get_role = getRoleCB;
582 aClass->get_attributes = getAttributesCB;
583 aClass->ref_state_set = refStateSetCB;
584 aClass->ref_relation_set = refRelationSetCB;
586 aClass->initialize = initializeCB;
588 gobject_class->finalize = finalizeCB;
590 mai_atk_object_signals [ACTIVATE] =
591 g_signal_new ("activate",
592 MAI_TYPE_ATK_OBJECT,
593 G_SIGNAL_RUN_LAST,
594 0, /* default signal handler */
595 NULL, NULL,
596 g_cclosure_marshal_VOID__VOID,
597 G_TYPE_NONE, 0);
598 mai_atk_object_signals [CREATE] =
599 g_signal_new ("create",
600 MAI_TYPE_ATK_OBJECT,
601 G_SIGNAL_RUN_LAST,
602 0, /* default signal handler */
603 NULL, NULL,
604 g_cclosure_marshal_VOID__VOID,
605 G_TYPE_NONE, 0);
606 mai_atk_object_signals [DEACTIVATE] =
607 g_signal_new ("deactivate",
608 MAI_TYPE_ATK_OBJECT,
609 G_SIGNAL_RUN_LAST,
610 0, /* default signal handler */
611 NULL, NULL,
612 g_cclosure_marshal_VOID__VOID,
613 G_TYPE_NONE, 0);
614 mai_atk_object_signals [DESTROY] =
615 g_signal_new ("destroy",
616 MAI_TYPE_ATK_OBJECT,
617 G_SIGNAL_RUN_LAST,
618 0, /* default signal handler */
619 NULL, NULL,
620 g_cclosure_marshal_VOID__VOID,
621 G_TYPE_NONE, 0);
622 mai_atk_object_signals [MAXIMIZE] =
623 g_signal_new ("maximize",
624 MAI_TYPE_ATK_OBJECT,
625 G_SIGNAL_RUN_LAST,
626 0, /* default signal handler */
627 NULL, NULL,
628 g_cclosure_marshal_VOID__VOID,
629 G_TYPE_NONE, 0);
630 mai_atk_object_signals [MINIMIZE] =
631 g_signal_new ("minimize",
632 MAI_TYPE_ATK_OBJECT,
633 G_SIGNAL_RUN_LAST,
634 0, /* default signal handler */
635 NULL, NULL,
636 g_cclosure_marshal_VOID__VOID,
637 G_TYPE_NONE, 0);
638 mai_atk_object_signals [RESIZE] =
639 g_signal_new ("resize",
640 MAI_TYPE_ATK_OBJECT,
641 G_SIGNAL_RUN_LAST,
642 0, /* default signal handler */
643 NULL, NULL,
644 g_cclosure_marshal_VOID__VOID,
645 G_TYPE_NONE, 0);
646 mai_atk_object_signals [RESTORE] =
647 g_signal_new ("restore",
648 MAI_TYPE_ATK_OBJECT,
649 G_SIGNAL_RUN_LAST,
650 0, /* default signal handler */
651 NULL, NULL,
652 g_cclosure_marshal_VOID__VOID,
653 G_TYPE_NONE, 0);
657 void
658 initializeCB(AtkObject *aAtkObj, gpointer aData)
660 NS_ASSERTION((IS_MAI_OBJECT(aAtkObj)), "Invalid AtkObject");
661 NS_ASSERTION(aData, "Invalid Data to init AtkObject");
662 if (!aAtkObj || !aData)
663 return;
665 /* call parent init function */
666 /* AtkObjectClass has not a "initialize" function now,
667 * maybe it has later
670 if (ATK_OBJECT_CLASS(parent_class)->initialize)
671 ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
673 /* initialize object */
674 MAI_ATK_OBJECT(aAtkObj)->accWrap =
675 static_cast<nsAccessibleWrap*>(aData);
677 #ifdef MAI_LOGGING
678 ++sMaiAtkObjCreated;
679 #endif
680 MAI_LOG_DEBUG(("MaiAtkObj Create obj=%p for AccWrap=%p, all=%d, left=%d\n",
681 (void*)aAtkObj, (void*)aData, sMaiAtkObjCreated,
682 (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
685 void
686 finalizeCB(GObject *aObj)
688 if (!IS_MAI_OBJECT(aObj))
689 return;
690 NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nsnull, "AccWrap NOT null");
692 #ifdef MAI_LOGGING
693 ++sMaiAtkObjDeleted;
694 #endif
695 MAI_LOG_DEBUG(("MaiAtkObj Delete obj=%p, all=%d, left=%d\n",
696 (void*)aObj, sMaiAtkObjCreated,
697 (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
699 // call parent finalize function
700 // finalize of GObjectClass will unref the accessible parent if has
701 if (G_OBJECT_CLASS (parent_class)->finalize)
702 G_OBJECT_CLASS (parent_class)->finalize(aObj);
705 const gchar *
706 getNameCB(AtkObject *aAtkObj)
708 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
709 if (!accWrap) {
710 return nsnull;
713 /* nsIAccessible is responsible for the non-NULL name */
714 nsAutoString uniName;
715 nsresult rv = accWrap->GetName(uniName);
716 NS_ENSURE_SUCCESS(rv, nsnull);
718 NS_ConvertUTF8toUTF16 objName(aAtkObj->name);
719 if (!uniName.Equals(objName)) {
720 atk_object_set_name(aAtkObj,
721 NS_ConvertUTF16toUTF8(uniName).get());
723 return aAtkObj->name;
726 const gchar *
727 getDescriptionCB(AtkObject *aAtkObj)
729 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
730 if (!accWrap) {
731 return nsnull;
734 /* nsIAccessible is responsible for the non-NULL description */
735 nsAutoString uniDesc;
736 nsresult rv = accWrap->GetDescription(uniDesc);
737 NS_ENSURE_SUCCESS(rv, nsnull);
739 NS_ConvertUTF8toUTF16 objDesc(aAtkObj->description);
740 if (!uniDesc.Equals(objDesc)) {
741 atk_object_set_description(aAtkObj,
742 NS_ConvertUTF16toUTF8(uniDesc).get());
744 return aAtkObj->description;
747 AtkRole
748 getRoleCB(AtkObject *aAtkObj)
750 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
751 if (!accWrap) {
752 return ATK_ROLE_INVALID;
755 #ifdef DEBUG_A11Y
756 NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
757 "Does not support nsIAccessibleText when it should");
758 #endif
760 if (aAtkObj->role == ATK_ROLE_INVALID) {
761 PRUint32 accRole, atkRole;
762 nsresult rv = accWrap->GetRole(&accRole);
763 NS_ENSURE_SUCCESS(rv, ATK_ROLE_INVALID);
765 atkRole = atkRoleMap[accRole]; // map to the actual value
766 NS_ASSERTION(atkRoleMap[nsIAccessibleRole::ROLE_LAST_ENTRY] ==
767 kROLE_ATK_LAST_ENTRY, "ATK role map skewed");
768 aAtkObj->role = static_cast<AtkRole>(atkRole);
770 return aAtkObj->role;
773 AtkAttributeSet*
774 ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes)
776 if (!aAttributes)
777 return nsnull;
779 AtkAttributeSet *objAttributeSet = nsnull;
780 nsCOMPtr<nsISimpleEnumerator> propEnum;
781 nsresult rv = aAttributes->Enumerate(getter_AddRefs(propEnum));
782 NS_ENSURE_SUCCESS(rv, nsnull);
784 PRBool hasMore;
785 while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) {
786 nsCOMPtr<nsISupports> sup;
787 rv = propEnum->GetNext(getter_AddRefs(sup));
788 NS_ENSURE_SUCCESS(rv, objAttributeSet);
790 nsCOMPtr<nsIPropertyElement> propElem(do_QueryInterface(sup));
791 NS_ENSURE_TRUE(propElem, objAttributeSet);
793 nsCAutoString name;
794 rv = propElem->GetKey(name);
795 NS_ENSURE_SUCCESS(rv, objAttributeSet);
797 nsAutoString value;
798 rv = propElem->GetValue(value);
799 NS_ENSURE_SUCCESS(rv, objAttributeSet);
801 AtkAttribute *objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute));
802 objAttr->name = g_strdup(name.get());
803 objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get());
804 objAttributeSet = g_slist_prepend(objAttributeSet, objAttr);
807 //libspi will free it
808 return objAttributeSet;
811 AtkAttributeSet *
812 GetAttributeSet(nsIAccessible* aAccessible)
814 nsCOMPtr<nsIPersistentProperties> attributes;
815 aAccessible->GetAttributes(getter_AddRefs(attributes));
817 if (attributes) {
818 // Deal with attributes that we only need to expose in ATK
819 PRUint32 state;
820 aAccessible->GetState(&state, nsnull);
821 if (state & nsIAccessibleStates::STATE_HASPOPUP) {
822 // There is no ATK state for haspopup, must use object attribute to expose the same info
823 nsAutoString oldValueUnused;
824 attributes->SetStringProperty(NS_LITERAL_CSTRING("haspopup"), NS_LITERAL_STRING("true"),
825 oldValueUnused);
828 return ConvertToAtkAttributeSet(attributes);
831 return nsnull;
834 AtkAttributeSet *
835 getAttributesCB(AtkObject *aAtkObj)
837 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
839 return accWrap ? GetAttributeSet(accWrap) : nsnull;
842 AtkObject *
843 getParentCB(AtkObject *aAtkObj)
845 if (!aAtkObj->accessible_parent) {
846 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
847 if (!accWrap) {
848 return nsnull;
851 nsAccessible* accParent = accWrap->GetParent();
852 if (!accParent)
853 return nsnull;
855 AtkObject *parent = nsAccessibleWrap::GetAtkObject(accParent);
856 if (parent)
857 atk_object_set_parent(aAtkObj, parent);
859 return aAtkObj->accessible_parent;
862 gint
863 getChildCountCB(AtkObject *aAtkObj)
865 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
866 if (!accWrap || nsAccUtils::MustPrune(accWrap)) {
867 return 0;
870 return accWrap->GetEmbeddedChildCount();
873 AtkObject *
874 refChildCB(AtkObject *aAtkObj, gint aChildIndex)
876 // aChildIndex should not be less than zero
877 if (aChildIndex < 0) {
878 return nsnull;
881 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
882 if (!accWrap || nsAccUtils::MustPrune(accWrap)) {
883 return nsnull;
886 nsAccessible* accChild = accWrap->GetEmbeddedChildAt(aChildIndex);
887 if (!accChild)
888 return nsnull;
890 AtkObject* childAtkObj = nsAccessibleWrap::GetAtkObject(accChild);
892 NS_ASSERTION(childAtkObj, "Fail to get AtkObj");
893 if (!childAtkObj)
894 return nsnull;
895 g_object_ref(childAtkObj);
897 //this will addref parent
898 atk_object_set_parent(childAtkObj, aAtkObj);
899 return childAtkObj;
902 gint
903 getIndexInParentCB(AtkObject *aAtkObj)
905 // We don't use nsIAccessible::GetIndexInParent() because
906 // for ATK we don't want to include text leaf nodes as children
907 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
908 if (!accWrap) {
909 return -1;
912 nsAccessible *parent = accWrap->GetParent();
913 if (!parent) {
914 return -1; // No parent
917 return parent->GetIndexOfEmbeddedChild(accWrap);
920 static void TranslateStates(PRUint32 aState, const AtkStateMap *aStateMap,
921 AtkStateSet *aStateSet)
923 NS_ASSERTION(aStateSet, "Can't pass in null state set");
925 // Convert every state to an entry in AtkStateMap
926 PRUint32 stateIndex = 0;
927 PRUint32 bitMask = 1;
928 while (aStateMap[stateIndex].stateMapEntryType != kNoSuchState) {
929 if (aStateMap[stateIndex].atkState) { // There's potentially an ATK state for this
930 PRBool isStateOn = (aState & bitMask) != 0;
931 if (aStateMap[stateIndex].stateMapEntryType == kMapOpposite) {
932 isStateOn = !isStateOn;
934 if (isStateOn) {
935 atk_state_set_add_state(aStateSet, aStateMap[stateIndex].atkState);
938 // Map extended state
939 bitMask <<= 1;
940 ++ stateIndex;
944 AtkStateSet *
945 refStateSetCB(AtkObject *aAtkObj)
947 AtkStateSet *state_set = nsnull;
948 state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj);
950 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
951 if (!accWrap) {
952 TranslateStates(nsIAccessibleStates::EXT_STATE_DEFUNCT,
953 gAtkStateMapExt, state_set);
954 return state_set;
957 // Map states
958 PRUint32 accState = 0, accExtState = 0;
959 nsresult rv = accWrap->GetState(&accState, &accExtState);
960 NS_ENSURE_SUCCESS(rv, state_set);
962 TranslateStates(accState, gAtkStateMap, state_set);
963 TranslateStates(accExtState, gAtkStateMapExt, state_set);
965 return state_set;
968 AtkRelationSet *
969 refRelationSetCB(AtkObject *aAtkObj)
971 AtkRelationSet *relation_set = nsnull;
972 relation_set = ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
974 nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
975 if (!accWrap) {
976 return relation_set;
979 AtkRelation* relation;
981 PRUint32 relationType[] = {nsIAccessibleRelation::RELATION_LABELLED_BY,
982 nsIAccessibleRelation::RELATION_LABEL_FOR,
983 nsIAccessibleRelation::RELATION_NODE_CHILD_OF,
984 nsIAccessibleRelation::RELATION_CONTROLLED_BY,
985 nsIAccessibleRelation::RELATION_CONTROLLER_FOR,
986 nsIAccessibleRelation::RELATION_EMBEDS,
987 nsIAccessibleRelation::RELATION_FLOWS_TO,
988 nsIAccessibleRelation::RELATION_FLOWS_FROM,
989 nsIAccessibleRelation::RELATION_DESCRIBED_BY,
990 nsIAccessibleRelation::RELATION_DESCRIPTION_FOR,
993 for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(relationType); i++) {
994 relation = atk_relation_set_get_relation_by_type(relation_set, static_cast<AtkRelationType>(relationType[i]));
995 if (relation) {
996 atk_relation_set_remove(relation_set, relation);
999 nsCOMPtr<nsIAccessibleRelation> geckoRelation;
1000 nsresult rv = accWrap->GetRelationByType(relationType[i],
1001 getter_AddRefs(geckoRelation));
1002 if (NS_SUCCEEDED(rv) && geckoRelation) {
1003 PRUint32 targetsCount = 0;
1004 geckoRelation->GetTargetsCount(&targetsCount);
1005 if (targetsCount) {
1006 AtkObject** accessible_array = new AtkObject*[targetsCount];
1007 for (PRUint32 index = 0; index < targetsCount; index++) {
1008 nsCOMPtr<nsIAccessible> geckoTarget;
1009 geckoRelation->GetTarget(index, getter_AddRefs(geckoTarget));
1010 accessible_array[index] =
1011 nsAccessibleWrap::GetAtkObject(geckoTarget);
1014 relation = atk_relation_new(accessible_array, targetsCount,
1015 static_cast<AtkRelationType>(relationType[i]));
1016 atk_relation_set_add(relation_set, relation);
1017 g_object_unref(relation);
1019 delete [] accessible_array;
1024 return relation_set;
1027 // Check if aAtkObj is a valid MaiAtkObject, and return the nsAccessibleWrap
1028 // for it.
1029 nsAccessibleWrap *GetAccessibleWrap(AtkObject *aAtkObj)
1031 NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nsnull);
1032 nsAccessibleWrap *tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
1034 // Check if AccessibleWrap was deconstructed
1035 if (tmpAccWrap == nsnull) {
1036 return nsnull;
1039 NS_ENSURE_TRUE(tmpAccWrap->GetAtkObject() == aAtkObj, nsnull);
1041 nsApplicationAccessible *applicationAcc =
1042 nsAccessNode::GetApplicationAccessible();
1043 nsAccessibleWrap* tmpAppAccWrap =
1044 static_cast<nsAccessibleWrap*>(applicationAcc);
1046 if (tmpAppAccWrap != tmpAccWrap && !tmpAccWrap->IsValidObject())
1047 return nsnull;
1049 return tmpAccWrap;
1052 nsresult
1053 nsAccessibleWrap::HandleAccEvent(AccEvent* aEvent)
1055 nsresult rv = nsAccessible::HandleAccEvent(aEvent);
1056 NS_ENSURE_SUCCESS(rv, rv);
1058 return FirePlatformEvent(aEvent);
1061 nsresult
1062 nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
1064 nsAccessible *accessible = aEvent->GetAccessible();
1065 NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
1067 PRUint32 type = aEvent->GetEventType();
1069 AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);
1071 // We don't create ATK objects for nsIAccessible plain text leaves,
1072 // just return NS_OK in such case
1073 if (!atkObj) {
1074 NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW ||
1075 type == nsIAccessibleEvent::EVENT_HIDE,
1076 "Event other than SHOW and HIDE fired for plain text leaves");
1077 return NS_OK;
1080 nsAccessibleWrap *accWrap = GetAccessibleWrap(atkObj);
1081 if (!accWrap) {
1082 return NS_OK; // Node is shut down
1085 switch (type) {
1086 case nsIAccessibleEvent::EVENT_STATE_CHANGE:
1087 return FireAtkStateChangeEvent(aEvent, atkObj);
1089 case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
1090 case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
1091 return FireAtkTextChangedEvent(aEvent, atkObj);
1093 case nsIAccessibleEvent::EVENT_FOCUS:
1095 MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n"));
1096 nsRefPtr<nsRootAccessible> rootAccWrap = accWrap->GetRootAccessible();
1097 if (rootAccWrap && rootAccWrap->mActivated) {
1098 atk_focus_tracker_notify(atkObj);
1099 // Fire state change event for focus
1100 nsRefPtr<AccEvent> stateChangeEvent =
1101 new AccStateChangeEvent(accessible,
1102 nsIAccessibleStates::STATE_FOCUSED,
1103 PR_FALSE, PR_TRUE);
1104 return FireAtkStateChangeEvent(stateChangeEvent, atkObj);
1106 } break;
1108 case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
1110 MAI_LOG_DEBUG(("\n\nReceived: EVENT_VALUE_CHANGE\n"));
1111 nsCOMPtr<nsIAccessibleValue> value(do_QueryObject(accessible));
1112 if (value) { // Make sure this is a numeric value
1113 // Don't fire for MSAA string value changes (e.g. text editing)
1114 // ATK values are always numeric
1115 g_object_notify( (GObject*)atkObj, "accessible-value" );
1117 } break;
1119 case nsIAccessibleEvent::EVENT_SELECTION_CHANGED:
1120 MAI_LOG_DEBUG(("\n\nReceived: EVENT_SELECTION_CHANGED\n"));
1121 g_signal_emit_by_name(atkObj, "selection_changed");
1122 break;
1124 case nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED:
1125 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_SELECTION_CHANGED\n"));
1126 g_signal_emit_by_name(atkObj, "text_selection_changed");
1127 break;
1129 case nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED:
1131 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_CARET_MOVED\n"));
1133 AccCaretMoveEvent* caretMoveEvent = downcast_accEvent(aEvent);
1134 NS_ASSERTION(caretMoveEvent, "Event needs event data");
1135 if (!caretMoveEvent)
1136 break;
1138 PRInt32 caretOffset = caretMoveEvent->GetCaretOffset();
1140 MAI_LOG_DEBUG(("\n\nCaret postion: %d", caretOffset));
1141 g_signal_emit_by_name(atkObj,
1142 "text_caret_moved",
1143 // Curent caret position
1144 caretOffset);
1145 } break;
1147 case nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED:
1148 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_ATTRIBUTE_CHANGED\n"));
1150 g_signal_emit_by_name(atkObj,
1151 "text-attributes-changed");
1152 break;
1154 case nsIAccessibleEvent::EVENT_TABLE_MODEL_CHANGED:
1155 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_MODEL_CHANGED\n"));
1156 g_signal_emit_by_name(atkObj, "model_changed");
1157 break;
1159 case nsIAccessibleEvent::EVENT_TABLE_ROW_INSERT:
1161 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_INSERT\n"));
1162 AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1163 NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1165 PRInt32 rowIndex = tableEvent->GetIndex();
1166 PRInt32 numRows = tableEvent->GetCount();
1168 g_signal_emit_by_name(atkObj,
1169 "row_inserted",
1170 // After which the rows are inserted
1171 rowIndex,
1172 // The number of the inserted
1173 numRows);
1174 } break;
1176 case nsIAccessibleEvent::EVENT_TABLE_ROW_DELETE:
1178 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_DELETE\n"));
1179 AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1180 NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1182 PRInt32 rowIndex = tableEvent->GetIndex();
1183 PRInt32 numRows = tableEvent->GetCount();
1185 g_signal_emit_by_name(atkObj,
1186 "row_deleted",
1187 // After which the rows are deleted
1188 rowIndex,
1189 // The number of the deleted
1190 numRows);
1191 } break;
1193 case nsIAccessibleEvent::EVENT_TABLE_ROW_REORDER:
1195 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_ROW_REORDER\n"));
1196 g_signal_emit_by_name(atkObj, "row_reordered");
1197 break;
1200 case nsIAccessibleEvent::EVENT_TABLE_COLUMN_INSERT:
1202 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_INSERT\n"));
1203 AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1204 NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1206 PRInt32 colIndex = tableEvent->GetIndex();
1207 PRInt32 numCols = tableEvent->GetCount();
1209 g_signal_emit_by_name(atkObj,
1210 "column_inserted",
1211 // After which the columns are inserted
1212 colIndex,
1213 // The number of the inserted
1214 numCols);
1215 } break;
1217 case nsIAccessibleEvent::EVENT_TABLE_COLUMN_DELETE:
1219 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_DELETE\n"));
1220 AccTableChangeEvent* tableEvent = downcast_accEvent(aEvent);
1221 NS_ENSURE_TRUE(tableEvent, NS_ERROR_FAILURE);
1223 PRInt32 colIndex = tableEvent->GetIndex();
1224 PRInt32 numCols = tableEvent->GetCount();
1226 g_signal_emit_by_name(atkObj,
1227 "column_deleted",
1228 // After which the columns are deleted
1229 colIndex,
1230 // The number of the deleted
1231 numCols);
1232 } break;
1234 case nsIAccessibleEvent::EVENT_TABLE_COLUMN_REORDER:
1235 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TABLE_COLUMN_REORDER\n"));
1236 g_signal_emit_by_name(atkObj, "column_reordered");
1237 break;
1239 case nsIAccessibleEvent::EVENT_SECTION_CHANGED:
1240 MAI_LOG_DEBUG(("\n\nReceived: EVENT_SECTION_CHANGED\n"));
1241 g_signal_emit_by_name(atkObj, "visible_data_changed");
1242 break;
1244 case nsIAccessibleEvent::EVENT_SHOW:
1245 return FireAtkShowHideEvent(aEvent, atkObj, PR_TRUE);
1247 case nsIAccessibleEvent::EVENT_HIDE:
1248 return FireAtkShowHideEvent(aEvent, atkObj, PR_FALSE);
1251 * Because dealing with menu is very different between nsIAccessible
1252 * and ATK, and the menu activity is important, specially transfer the
1253 * following two event.
1254 * Need more verification by AT test.
1256 case nsIAccessibleEvent::EVENT_MENU_START:
1257 MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENU_START\n"));
1258 break;
1260 case nsIAccessibleEvent::EVENT_MENU_END:
1261 MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENU_END\n"));
1262 break;
1264 case nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE:
1266 MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_ACTIVATED\n"));
1267 nsRootAccessible *rootAcc =
1268 static_cast<nsRootAccessible *>(accessible);
1269 rootAcc->mActivated = PR_TRUE;
1270 guint id = g_signal_lookup ("activate", MAI_TYPE_ATK_OBJECT);
1271 g_signal_emit(atkObj, id, 0);
1273 // Always fire a current focus event after activation.
1274 rootAcc->FireCurrentFocusEvent();
1275 } break;
1277 case nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE:
1279 MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_DEACTIVATED\n"));
1280 nsRootAccessible *rootAcc =
1281 static_cast<nsRootAccessible *>(accessible);
1282 rootAcc->mActivated = PR_FALSE;
1283 guint id = g_signal_lookup ("deactivate", MAI_TYPE_ATK_OBJECT);
1284 g_signal_emit(atkObj, id, 0);
1285 } break;
1287 case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
1289 MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_COMPLETE\n"));
1290 g_signal_emit_by_name (atkObj, "load_complete");
1291 } break;
1293 case nsIAccessibleEvent::EVENT_DOCUMENT_RELOAD:
1295 MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_RELOAD\n"));
1296 g_signal_emit_by_name (atkObj, "reload");
1297 } break;
1299 case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_STOPPED:
1301 MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_STOPPED\n"));
1302 g_signal_emit_by_name (atkObj, "load_stopped");
1303 } break;
1305 case nsIAccessibleEvent::EVENT_MENUPOPUP_START:
1306 MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUPOPUP_START\n"));
1307 atk_focus_tracker_notify(atkObj); // fire extra focus event
1308 atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, PR_TRUE);
1309 atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, PR_TRUE);
1310 break;
1312 case nsIAccessibleEvent::EVENT_MENUPOPUP_END:
1313 MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUPOPUP_END\n"));
1314 atk_object_notify_state_change(atkObj, ATK_STATE_VISIBLE, PR_FALSE);
1315 atk_object_notify_state_change(atkObj, ATK_STATE_SHOWING, PR_FALSE);
1316 break;
1319 return NS_OK;
1322 nsresult
1323 nsAccessibleWrap::FireAtkStateChangeEvent(AccEvent* aEvent,
1324 AtkObject *aObject)
1326 MAI_LOG_DEBUG(("\n\nReceived: EVENT_STATE_CHANGE\n"));
1328 AccStateChangeEvent* event = downcast_accEvent(aEvent);
1329 NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
1331 PRUint32 state = event->GetState();
1332 PRBool isExtra = event->IsExtraState();
1333 PRBool isEnabled = event->IsStateEnabled();
1335 PRInt32 stateIndex = AtkStateMap::GetStateIndexFor(state);
1336 if (stateIndex >= 0) {
1337 const AtkStateMap *atkStateMap = isExtra ? gAtkStateMapExt : gAtkStateMap;
1338 NS_ASSERTION(atkStateMap[stateIndex].stateMapEntryType != kNoSuchState,
1339 "No such state");
1341 if (atkStateMap[stateIndex].atkState != kNone) {
1342 NS_ASSERTION(atkStateMap[stateIndex].stateMapEntryType != kNoStateChange,
1343 "State changes should not fired for this state");
1345 if (atkStateMap[stateIndex].stateMapEntryType == kMapOpposite)
1346 isEnabled = !isEnabled;
1348 // Fire state change for first state if there is one to map
1349 atk_object_notify_state_change(aObject,
1350 atkStateMap[stateIndex].atkState,
1351 isEnabled);
1355 return NS_OK;
1358 nsresult
1359 nsAccessibleWrap::FireAtkTextChangedEvent(AccEvent* aEvent,
1360 AtkObject *aObject)
1362 MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));
1364 AccTextChangeEvent* event = downcast_accEvent(aEvent);
1365 NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
1367 PRInt32 start = event->GetStartOffset();
1368 PRUint32 length = event->GetLength();
1369 PRBool isInserted = event->IsTextInserted();
1371 PRBool isFromUserInput = aEvent->IsFromUserInput();
1373 char *signal_name = g_strconcat(isInserted ? "text_changed::insert" : "text_changed::delete",
1374 isFromUserInput ? "" : kNonUserInputEvent, NULL);
1375 g_signal_emit_by_name(aObject, signal_name, start, length);
1376 g_free (signal_name);
1378 return NS_OK;
1381 nsresult
1382 nsAccessibleWrap::FireAtkShowHideEvent(AccEvent* aEvent,
1383 AtkObject *aObject, PRBool aIsAdded)
1385 if (aIsAdded)
1386 MAI_LOG_DEBUG(("\n\nReceived: Show event\n"));
1387 else
1388 MAI_LOG_DEBUG(("\n\nReceived: Hide event\n"));
1390 PRInt32 indexInParent = getIndexInParentCB(aObject);
1391 AtkObject *parentObject = getParentCB(aObject);
1392 NS_ENSURE_STATE(parentObject);
1394 PRBool isFromUserInput = aEvent->IsFromUserInput();
1395 char *signal_name = g_strconcat(aIsAdded ? "children_changed::add" : "children_changed::remove",
1396 isFromUserInput ? "" : kNonUserInputEvent, NULL);
1397 g_signal_emit_by_name(parentObject, signal_name, indexInParent, aObject, NULL);
1398 g_free(signal_name);
1400 return NS_OK;