/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* vim:expandtab:shiftwidth=4:tabstop=4: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Sun Microsystems, Inc. * Portions created by Sun Microsystems are Copyright (C) 2002 Sun * Microsystems, Inc. All Rights Reserved. * * Original Author: Bolian Yin (bolian.yin@sun.com) * * Contributor(s): John Sun (john.sun@sun.com) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsMai.h" #include "nsAccessibleWrap.h" #include "nsAppRootAccessible.h" #include "nsString.h" #include "nsMaiInterfaceComponent.h" #include "nsMaiInterfaceAction.h" #include "nsMaiInterfaceText.h" #include "nsMaiInterfaceEditableText.h" #include "nsMaiInterfaceSelection.h" #include "nsMaiInterfaceValue.h" #include "nsMaiInterfaceHypertext.h" #include "nsMaiInterfaceTable.h" /* MaiAtkObject */ enum { ACTIVATE, CREATE, DEACTIVATE, DESTROY, MAXIMIZE, MINIMIZE, RESIZE, RESTORE, LAST_SIGNAL }; /** * This MaiAtkObject is a thin wrapper, in the MAI namespace, for AtkObject */ 00073 struct MaiAtkObject { AtkObject parent; /* * The nsAccessibleWrap whose properties and features are exported * via this object instance. */ nsAccessibleWrap *accWrap; }; struct MaiAtkObjectClass { AtkObjectClass parent_class; }; static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, }; #ifdef MAI_LOGGING PRInt32 sMaiAtkObjCreated = 0; PRInt32 sMaiAtkObjDeleted = 0; #endif G_BEGIN_DECLS /* callbacks for MaiAtkObject */ static void classInitCB(AtkObjectClass *aClass); static void initializeCB(AtkObject *aAtkObj, gpointer aData); static void finalizeCB(GObject *aObj); /* callbacks for AtkObject virtual functions */ static const gchar* getNameCB (AtkObject *aAtkObj); static const gchar* getDescriptionCB (AtkObject *aAtkObj); static AtkRole getRoleCB(AtkObject *aAtkObj); static AtkObject* getParentCB(AtkObject *aAtkObj); static gint getChildCountCB(AtkObject *aAtkObj); static AtkObject* refChildCB(AtkObject *aAtkObj, gint aChildIndex); static gint getIndexInParentCB(AtkObject *aAtkObj); static AtkStateSet* refStateSetCB(AtkObject *aAtkObj); static AtkRelationSet* refRelationSetCB(AtkObject *aAtkObj); /* the missing atkobject virtual functions */ /* static AtkLayer getLayerCB(AtkObject *aAtkObj); static gint getMdiZorderCB(AtkObject *aAtkObj); static void SetNameCB(AtkObject *aAtkObj, const gchar *name); static void SetDescriptionCB(AtkObject *aAtkObj, const gchar *description); static void SetParentCB(AtkObject *aAtkObj, AtkObject *parent); static void SetRoleCB(AtkObject *aAtkObj, AtkRole role); static guint ConnectPropertyChangeHandlerCB( AtkObject *aObj, AtkPropertyChangeHandler *handler); static void RemovePropertyChangeHandlerCB( AtkObject *aAtkObj, guint handler_id); static void InitializeCB(AtkObject *aAtkObj, gpointer data); static void ChildrenChangedCB(AtkObject *aAtkObj, guint change_index, gpointer changed_child); static void FocusEventCB(AtkObject *aAtkObj, gboolean focus_in); static void PropertyChangeCB(AtkObject *aAtkObj, AtkPropertyValues *values); static void StateChangeCB(AtkObject *aAtkObj, const gchar *name, gboolean state_set); static void VisibleDataChangedCB(AtkObject *aAtkObj); */ G_END_DECLS static GType GetMaiAtkType(const PRUint32 & interfaceCount, MaiInterface **interfaces); static const char * GetUniqueMaiAtkTypeName(void); static gpointer parent_class = NULL; GType mai_atk_object_get_type(void) { static GType type = 0; if (!type) { static const GTypeInfo tinfo = { sizeof(MaiAtkObjectClass), (GBaseInitFunc)NULL, (GBaseFinalizeFunc)NULL, (GClassInitFunc)classInitCB, (GClassFinalizeFunc)NULL, NULL, /* class data */ sizeof(MaiAtkObject), /* instance size */ 0, /* nb preallocs */ (GInstanceInitFunc)NULL, NULL /* value table */ }; type = g_type_register_static(ATK_TYPE_OBJECT, "MaiAtkObject", &tinfo, GTypeFlags(0)); } return type; } #ifdef MAI_LOGGING PRInt32 nsAccessibleWrap::mAccWrapCreated = 0; PRInt32 nsAccessibleWrap::mAccWrapDeleted = 0; #endif nsAccessibleWrap::nsAccessibleWrap(nsIDOMNode* aNode, nsIWeakReference *aShell) : nsAccessible(aNode, aShell), mMaiAtkObject(nsnull), mInterfaces(nsnull), mInterfaceCount(0) { #ifdef MAI_LOGGING ++mAccWrapCreated; #endif MAI_LOG_DEBUG(("==nsAccessibleWrap creating: this=%p,total=%d left=%d\n", (void*)this, mAccWrapCreated, (mAccWrapCreated-mAccWrapDeleted))); } nsAccessibleWrap::~nsAccessibleWrap() { #ifdef MAI_LOGGING ++mAccWrapDeleted; #endif MAI_LOG_DEBUG(("==nsAccessibleWrap deleting: this=%p,total=%d left=%d\n", (void*)this, mAccWrapDeleted, (mAccWrapCreated-mAccWrapDeleted))); if (mMaiAtkObject) { MAI_ATK_OBJECT(mMaiAtkObject)->accWrap = nsnull; g_object_unref(mMaiAtkObject); } if (mInterfaces) { for (int index = 0; index < MAI_INTERFACE_NUM; ++index) delete mInterfaces[index]; delete [] mInterfaces; } } NS_IMETHODIMP nsAccessibleWrap::GetExtState(PRUint32 *aState) { PRUint32 state; nsAccessible::GetState(&state); if (!(state & STATE_INVISIBLE)) *aState |= EXT_STATE_SHOWING; return NS_OK; } NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible) { *aOutAccessible = nsnull; if (!mMaiAtkObject) { CreateMaiInterfaces(); mMaiAtkObject = NS_REINTERPRET_CAST(AtkObject *, g_object_new(GetMaiAtkType(mInterfaceCount, mInterfaces), NULL)); NS_ENSURE_TRUE(mMaiAtkObject, NS_ERROR_OUT_OF_MEMORY); atk_object_initialize(mMaiAtkObject, this); mMaiAtkObject->role = ATK_ROLE_INVALID; mMaiAtkObject->layer = ATK_LAYER_INVALID; } *aOutAccessible = mMaiAtkObject; return NS_OK; } AtkObject * nsAccessibleWrap::GetAtkObject(void) { void *atkObj = nsnull; GetNativeInterface(&atkObj); return NS_STATIC_CAST(AtkObject *, atkObj); } /* private */ nsresult nsAccessibleWrap::CreateMaiInterfaces(void) { typedef MaiInterface * MaiInterfacePointer; if (!mInterfaces) { mInterfaces = new MaiInterfacePointer[MAI_INTERFACE_NUM]; for (PRUint16 index = 0; index < MAI_INTERFACE_NUM; ++index) { mInterfaces[index] = nsnull; } NS_ENSURE_TRUE(mInterfaces, NS_ERROR_OUT_OF_MEMORY); } // Add Interfaces for each nsIAccessible.ext interfaces nsresult rv; // the Component interface are supported by all nsIAccessible MaiInterfaceComponent *maiInterfaceComponent = new MaiInterfaceComponent(this); NS_ENSURE_TRUE(maiInterfaceComponent, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceComponent); NS_ENSURE_SUCCESS(rv, rv); // Add Action interface if the action count is more than zero. PRUint8 actionCount = 0; rv = GetNumActions(&actionCount); if (NS_SUCCEEDED(rv) && actionCount > 0) { MaiInterfaceAction *maiInterfaceAction = new MaiInterfaceAction(this); NS_ENSURE_TRUE(maiInterfaceAction, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceAction); NS_ENSURE_SUCCESS(rv, rv); } PRUint32 accRole; rv = GetRole(&accRole); if (accRole != nsIAccessible::ROLE_HTML_CONTAINER) { //nsIAccessibleText nsCOMPtr<nsIAccessibleText> accessInterfaceText; QueryInterface(NS_GET_IID(nsIAccessibleText), getter_AddRefs(accessInterfaceText)); if (accessInterfaceText) { MaiInterfaceText *maiInterfaceText = new MaiInterfaceText(this); NS_ENSURE_TRUE(maiInterfaceText, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceText); NS_ENSURE_SUCCESS(rv, rv); } //nsIAccessibleEditableText nsCOMPtr<nsIAccessibleEditableText> accessInterfaceEditableText; QueryInterface(NS_GET_IID(nsIAccessibleEditableText), getter_AddRefs(accessInterfaceEditableText)); if (accessInterfaceEditableText) { MaiInterfaceEditableText *maiInterfaceEditableText = new MaiInterfaceEditableText(this); NS_ENSURE_TRUE(maiInterfaceEditableText, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceEditableText); NS_ENSURE_SUCCESS(rv, rv); } } //nsIAccessibleSelection nsCOMPtr<nsIAccessibleSelectable> accessInterfaceSelection; QueryInterface(NS_GET_IID(nsIAccessibleSelectable), getter_AddRefs(accessInterfaceSelection)); if (accessInterfaceSelection) { MaiInterfaceSelection *maiInterfaceSelection = new MaiInterfaceSelection(this); NS_ENSURE_TRUE(maiInterfaceSelection, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceSelection); NS_ENSURE_SUCCESS(rv, rv); } //nsIAccessibleValue nsCOMPtr<nsIAccessibleValue> accessInterfaceValue; QueryInterface(NS_GET_IID(nsIAccessibleValue), getter_AddRefs(accessInterfaceValue)); if (accessInterfaceValue) { MaiInterfaceValue *maiInterfaceValue = new MaiInterfaceValue(this); NS_ENSURE_TRUE(maiInterfaceValue, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceValue); NS_ENSURE_SUCCESS(rv, rv); } //nsIAccessibleHypertext PRInt32 linkCount = 0; nsCOMPtr<nsIAccessibleHyperText> accessInterfaceHypertext; QueryInterface(NS_GET_IID(nsIAccessibleHyperText), getter_AddRefs(accessInterfaceHypertext)); if (accessInterfaceHypertext) { rv = accessInterfaceHypertext->GetLinks(&linkCount); if (NS_SUCCEEDED(rv) && (linkCount > 0)) { MaiInterfaceHypertext *maiInterfaceHypertext = new MaiInterfaceHypertext(this, mWeakShell); NS_ENSURE_TRUE(maiInterfaceHypertext, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceHypertext); NS_ENSURE_SUCCESS(rv, rv); } } //nsIAccessibleTable if (accRole == nsIAccessible::ROLE_TREE_TABLE) { // In most cases, html table is used as container to arrange the webpage, // not to represent a "real" table with practical colum, colum heaer, row. // So, only add maiInterfaceTable for XUL table. nsCOMPtr<nsIAccessibleTable> accessInterfaceTable; QueryInterface(NS_GET_IID(nsIAccessibleTable), getter_AddRefs(accessInterfaceTable)); if (accessInterfaceTable) { MaiInterfaceTable *maiInterfaceTable = new MaiInterfaceTable(this); NS_ENSURE_TRUE(maiInterfaceTable, NS_ERROR_OUT_OF_MEMORY); rv = AddMaiInterface(maiInterfaceTable); NS_ENSURE_SUCCESS(rv, rv); } } return rv; } nsresult nsAccessibleWrap::AddMaiInterface(MaiInterface *aMaiIface) { NS_ENSURE_ARG_POINTER(aMaiIface); MaiInterfaceType aMaiIfaceType = aMaiIface->GetType(); if ((aMaiIfaceType <= MAI_INTERFACE_INVALID) || (aMaiIfaceType >= MAI_INTERFACE_NUM)) return NS_ERROR_FAILURE; // if same type of If has been added, release previous one if (mInterfaces[aMaiIfaceType]) { delete mInterfaces[aMaiIfaceType]; } mInterfaces[aMaiIfaceType] = aMaiIface; mInterfaceCount++; return NS_OK; } MaiInterface * nsAccessibleWrap::GetMaiInterface(PRInt16 aIfaceType) { NS_ENSURE_TRUE(aIfaceType > MAI_INTERFACE_INVALID, nsnull); NS_ENSURE_TRUE(aIfaceType < MAI_INTERFACE_NUM, nsnull); return mInterfaces[aIfaceType]; } static GType GetMaiAtkType(const PRUint32 & interfaceCount, MaiInterface **interfaces) { GType type; static const GTypeInfo tinfo = { sizeof(MaiAtkObjectClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) NULL, (GClassFinalizeFunc) NULL, NULL, /* class data */ sizeof(MaiAtkObject), /* instance size */ 0, /* nb preallocs */ (GInstanceInitFunc) NULL, NULL /* value table */ }; if (interfaceCount == 0) return MAI_TYPE_ATK_OBJECT; type = g_type_register_static(MAI_TYPE_ATK_OBJECT, GetUniqueMaiAtkTypeName(), &tinfo, GTypeFlags(0)); for (int index = 0; index < MAI_INTERFACE_NUM; index++) { if (!interfaces[index]) continue; g_type_add_interface_static(type, interfaces[index]->GetAtkType(), interfaces[index]->GetInterfaceInfo()); } return type; } static const char * GetUniqueMaiAtkTypeName(void) { #define MAI_ATK_TYPE_NAME_LEN (30) /* 10+sizeof(gulong)*8/4+1 < 30 */ static PRUint32 atkTypeNameIndex = 0; static gchar namePrefix[] = "MaiAtkType"; /* size = 10 */ static gchar name[MAI_ATK_TYPE_NAME_LEN + 1]; sprintf(name, "%s%x", namePrefix, atkTypeNameIndex++); name[MAI_ATK_TYPE_NAME_LEN] = '\0'; MAI_LOG_DEBUG(("MaiWidget::LastedTypeName=%s\n", name)); return name; } /****************************************************************************** The following nsIAccessible states aren't translated, just ignored. STATE_MIXED: For a three-state check box. STATE_READONLY: The object is designated read-only. STATE_HOTTRACKED: Means its appearance has changed to indicate mouse over it. STATE_FLOATING: Not supported yet. STATE_MARQUEED: Indicate scrolling or moving text or graphics. STATE_ANIMATED: STATE_OFFSCREEN: Has no on-screen representation. STATE_MOVEABLE: STATE_SELFVOICING: The object has self-TTS. STATE_LINKED: The object is formatted as a hyperlink. STATE_TRAVERSE: The object is a hyperlink that has been visited. STATE_EXTSELECTABLE: Indicates that an object extends its selectioin. STATE_ALERT_LOW: Not supported yet. STATE_ALERT_MEDIUM: Not supported yet. STATE_ALERT_HIGH: Not supported yet. STATE_PROTECTED: The object is a password-protected edit control. STATE_HASPOPUP: Object displays a pop-up menu or window when invoked. Returned AtkStatusSet never contain the following AtkStates. ATK_STATE_ARMED: Indicates that the object is armed. ATK_STATE_DEFUNCT: Indicates the user interface object corresponding to thus object no longer exists. ATK_STATE_HORIZONTAL:Indicates the orientation of this object is horizontal. ATK_STATE_ICONIFIED: ATK_STATE_OPAQUE: Indicates the object paints every pixel within its rectangular region ATK_STATE_STALE: The index associated with this object has changed since the user accessed the object ******************************************************************************/ void nsAccessibleWrap::TranslateStates(PRUint32 aState, PRUint32 aExtState, void *aAtkStateSet) { if (!aAtkStateSet) return; AtkStateSet *state_set = NS_STATIC_CAST(AtkStateSet *, aAtkStateSet); if (aState & nsIAccessible::STATE_SELECTED) atk_state_set_add_state (state_set, ATK_STATE_SELECTED); if (aState & nsIAccessible::STATE_FOCUSED) atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); if (aState & nsIAccessible::STATE_PRESSED) atk_state_set_add_state (state_set, ATK_STATE_PRESSED); if (aState & nsIAccessible::STATE_CHECKED) atk_state_set_add_state (state_set, ATK_STATE_CHECKED); if (aState & nsIAccessible::STATE_EXPANDED) atk_state_set_add_state (state_set, ATK_STATE_EXPANDED); if (aState & nsIAccessible::STATE_COLLAPSED) atk_state_set_add_state (state_set, ATK_STATE_EXPANDABLE); // The control can't accept input at this time if (aState & nsIAccessible::STATE_BUSY) atk_state_set_add_state (state_set, ATK_STATE_BUSY); if (aState & nsIAccessible::STATE_FOCUSABLE) atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE); if (!(aState & nsIAccessible::STATE_INVISIBLE)) atk_state_set_add_state (state_set, ATK_STATE_VISIBLE); if (aState & nsIAccessible::STATE_SELECTABLE) atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE); if (aState & nsIAccessible::STATE_SIZEABLE) atk_state_set_add_state (state_set, ATK_STATE_RESIZABLE); if (aState & nsIAccessible::STATE_MULTISELECTABLE) atk_state_set_add_state (state_set, ATK_STATE_MULTISELECTABLE); if (!(aState & nsIAccessible::STATE_UNAVAILABLE)) { atk_state_set_add_state (state_set, ATK_STATE_ENABLED); atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); } if (aState & nsIAccessible::STATE_INVALID) atk_state_set_add_state (state_set, ATK_STATE_INVALID); #ifdef MAI_HAS_ATK_STATE_DEFAULT if (aState & nsIAccessible::STATE_DEFAULT) atk_state_set_add_state (state_set, ATK_STATE_DEFAULT); #endif #ifdef MAI_HAS_ATK_STATE_REQUIRED if (aState & nsIAccessible::STATE_REQUIRED) atk_state_set_add_state (state_set, ATK_STATE_REQUIRED); #endif // The following state is // Extended state flags (for now non-MSAA, for Java and Gnome/ATK support) if (aExtState & nsIAccessible::EXT_STATE_ACTIVE) atk_state_set_add_state (state_set, ATK_STATE_ACTIVE); if (aExtState & nsIAccessible::EXT_STATE_EXPANDABLE) atk_state_set_add_state (state_set, ATK_STATE_EXPANDABLE); if (aExtState & nsIAccessible::EXT_STATE_MODAL) atk_state_set_add_state (state_set, ATK_STATE_MODAL); if (aExtState & nsIAccessible::EXT_STATE_MULTI_LINE) atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE); if (aExtState & nsIAccessible::EXT_STATE_SENSITIVE) atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE); if (aExtState & nsIAccessible::EXT_STATE_SHOWING) atk_state_set_add_state (state_set, ATK_STATE_SHOWING); if (aExtState & nsIAccessible::EXT_STATE_SINGLE_LINE) atk_state_set_add_state (state_set, ATK_STATE_SINGLE_LINE); if (aExtState & nsIAccessible::EXT_STATE_TRANSIENT) atk_state_set_add_state (state_set, ATK_STATE_TRANSIENT); if (aExtState & nsIAccessible::EXT_STATE_VERTICAL) atk_state_set_add_state (state_set, ATK_STATE_VERTICAL); if (aState & nsIAccessible::EXT_STATE_EDITABLE) atk_state_set_add_state (state_set, ATK_STATE_EDITABLE); } PRBool nsAccessibleWrap::IsValidObject() { // to ensure we are not shut down return (mDOMNode != nsnull); } /* static functions for ATK callbacks */ void classInitCB(AtkObjectClass *aClass) { GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); parent_class = g_type_class_peek_parent(aClass); aClass->get_name = getNameCB; aClass->get_description = getDescriptionCB; aClass->get_parent = getParentCB; aClass->get_n_children = getChildCountCB; aClass->ref_child = refChildCB; aClass->get_index_in_parent = getIndexInParentCB; aClass->get_role = getRoleCB; aClass->ref_state_set = refStateSetCB; aClass->ref_relation_set = refRelationSetCB; aClass->initialize = initializeCB; gobject_class->finalize = finalizeCB; mai_atk_object_signals [ACTIVATE] = g_signal_new ("activate", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); mai_atk_object_signals [CREATE] = g_signal_new ("create", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); mai_atk_object_signals [DEACTIVATE] = g_signal_new ("deactivate", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); mai_atk_object_signals [DESTROY] = g_signal_new ("destroy", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); mai_atk_object_signals [MAXIMIZE] = g_signal_new ("maximize", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); mai_atk_object_signals [MINIMIZE] = g_signal_new ("minimize", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); mai_atk_object_signals [RESIZE] = g_signal_new ("resize", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); mai_atk_object_signals [RESTORE] = g_signal_new ("restore", MAI_TYPE_ATK_OBJECT, G_SIGNAL_RUN_LAST, 0, /* default signal handler */ NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } void initializeCB(AtkObject *aAtkObj, gpointer aData) { NS_ASSERTION((MAI_IS_ATK_OBJECT(aAtkObj)), "Invalid AtkObject"); NS_ASSERTION(aData, "Invalid Data to init AtkObject"); if (!aAtkObj || !aData) return; /* call parent init function */ /* AtkObjectClass has not a "initialize" function now, * maybe it has later */ if (ATK_OBJECT_CLASS(parent_class)->initialize) ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData); /* initialize object */ MAI_ATK_OBJECT(aAtkObj)->accWrap = NS_STATIC_CAST(nsAccessibleWrap*, aData); #ifdef MAI_LOGGING ++sMaiAtkObjCreated; #endif MAI_LOG_DEBUG(("MaiAtkObj Create obj=%p for AccWrap=%p, all=%d, left=%d\n", (void*)aAtkObj, (void*)aData, sMaiAtkObjCreated, (sMaiAtkObjCreated-sMaiAtkObjDeleted))); } void finalizeCB(GObject *aObj) { if (!MAI_IS_ATK_OBJECT(aObj)) return; NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nsnull, "AccWrap NOT null"); #ifdef MAI_LOGGING ++sMaiAtkObjDeleted; #endif MAI_LOG_DEBUG(("MaiAtkObj Delete obj=%p, all=%d, left=%d\n", (void*)aObj, sMaiAtkObjCreated, (sMaiAtkObjCreated-sMaiAtkObjDeleted))); // call parent finalize function // finalize of GObjectClass will unref the accessible parent if has if (G_OBJECT_CLASS (parent_class)->finalize) G_OBJECT_CLASS (parent_class)->finalize(aObj); } const gchar * getNameCB(AtkObject *aAtkObj) { NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull); nsAutoString uniName; nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; /* nsIAccessible is responsible for the non-NULL name */ nsresult rv = accWrap->GetName(uniName); NS_ENSURE_SUCCESS(rv, nsnull); if (uniName.Length() > 0) { NS_ConvertUTF8toUCS2 objName(aAtkObj->name); if (!uniName.Equals(objName)) { atk_object_set_name(aAtkObj, NS_ConvertUCS2toUTF8(uniName).get()); } } return aAtkObj->name; } const gchar * getDescriptionCB(AtkObject *aAtkObj) { NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull); if (!aAtkObj->description) { gint len; nsAutoString uniDesc; nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; /* nsIAccessible is responsible for the non-NULL description */ nsresult rv = accWrap->GetDescription(uniDesc); NS_ENSURE_SUCCESS(rv, nsnull); len = uniDesc.Length(); if (len > 0) { atk_object_set_description(aAtkObj, NS_ConvertUCS2toUTF8(uniDesc).get()); } } return aAtkObj->description; } AtkRole getRoleCB(AtkObject *aAtkObj) { NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), ATK_ROLE_INVALID); if (aAtkObj->role == ATK_ROLE_INVALID) { nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; PRUint32 accRole; nsresult rv = accWrap->GetFinalRole(&accRole); NS_ENSURE_SUCCESS(rv, ATK_ROLE_INVALID); //the cross-platform Accessible object returns the same value for //both "ROLE_MENUITEM" and "ROLE_MENUPOPUP" if (accRole == nsIAccessible::ROLE_MENUITEM) { PRInt32 childCount = 0; accWrap->GetChildCount(&childCount); if (childCount > 0) accRole = nsIAccessible::ROLE_MENUPOPUP; } else if (accRole == nsIAccessible::ROLE_LINK) { //ATK doesn't have role-link now //register it on runtime static AtkRole linkRole = (AtkRole)0; if (linkRole == 0) { linkRole = atk_role_register("hyper link"); } accRole = linkRole; } aAtkObj->role = NS_STATIC_CAST(AtkRole, accRole); } return aAtkObj->role; } AtkObject * getParentCB(AtkObject *aAtkObj) { NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull); nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; nsCOMPtr<nsIAccessible> accParent; nsresult rv = accWrap->GetParent(getter_AddRefs(accParent)); if (NS_FAILED(rv) || !accParent) return nsnull; nsIAccessible *tmpParent = accParent; nsAccessibleWrap *accWrapParent = NS_STATIC_CAST(nsAccessibleWrap *, tmpParent); AtkObject *parentAtkObj = accWrapParent->GetAtkObject(); if (parentAtkObj && !aAtkObj->accessible_parent) { atk_object_set_parent(aAtkObj, parentAtkObj); } return parentAtkObj; } gint getChildCountCB(AtkObject *aAtkObj) { NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), 0); nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; PRInt32 count = 0; accWrap->GetChildCount(&count); return count; } AtkObject * refChildCB(AtkObject *aAtkObj, gint aChildIndex) { NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull); nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; nsresult rv; nsCOMPtr<nsIAccessible> accChild; rv = accWrap->GetChildAt(aChildIndex, getter_AddRefs(accChild)); if (NS_FAILED(rv) || !accChild) return nsnull; nsIAccessible *tmpAccChild = accChild; nsAccessibleWrap *accWrapChild = NS_STATIC_CAST(nsAccessibleWrap*, tmpAccChild); //this will addref parent AtkObject *childAtkObj = accWrapChild->GetAtkObject(); NS_ASSERTION(childAtkObj, "Fail to get AtkObj"); if (!childAtkObj) return nsnull; atk_object_set_parent(childAtkObj, accWrap->GetAtkObject()); g_object_ref(childAtkObj); return childAtkObj; } gint getIndexInParentCB(AtkObject *aAtkObj) { NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), -1); nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; PRInt32 currentIndex = -1; accWrap->GetIndexInParent(¤tIndex); return currentIndex; } AtkStateSet * refStateSetCB(AtkObject *aAtkObj) { AtkStateSet *state_set = nsnull; state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj); NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), state_set); nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; PRUint32 accState = 0; nsresult rv = accWrap->GetFinalState(&accState); NS_ENSURE_SUCCESS(rv, state_set); PRUint32 accExtState = 0; rv = accWrap->GetExtState(&accExtState); NS_ENSURE_SUCCESS(rv, state_set); if ((accState == 0) && (accExtState == 0)) return state_set; nsAccessibleWrap::TranslateStates(accState, accExtState, state_set); return state_set; } AtkRelationSet * refRelationSetCB(AtkObject *aAtkObj) { AtkRelationSet *relation_set = nsnull; relation_set = ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj); NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), relation_set); nsAccessibleWrap *accWrap = NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap; AtkObject *accessible_array[1]; AtkRelation* relation; PRUint32 relationType[2] = {nsIAccessible::RELATION_LABELLED_BY, nsIAccessible::RELATION_LABEL_FOR}; for (PRUint32 i = 0; i <= 1; i++) { if (!atk_relation_set_contains(relation_set, NS_STATIC_CAST(AtkRelationType, relationType[i]))) { nsIAccessible* accRelated; nsresult rv = accWrap->GetAccessibleRelated(relationType[i], &accRelated); if (NS_SUCCEEDED(rv) && accRelated) { accessible_array[0] = NS_STATIC_CAST(nsAccessibleWrap*, accRelated)->GetAtkObject(); relation = atk_relation_new(accessible_array, 1, NS_STATIC_CAST(AtkRelationType, relationType[i])); atk_relation_set_add(relation_set, relation); } } } return relation_set; } // Check if aAtkObj is a valid MaiAtkObject nsresult CheckMaiAtkObject(AtkObject *aAtkObj) { NS_ENSURE_ARG(MAI_IS_ATK_OBJECT(aAtkObj)); nsAccessibleWrap * tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap; if (tmpAccWrap == nsnull) return NS_ERROR_INVALID_POINTER; if (tmpAccWrap != nsAppRootAccessible::Create() && !tmpAccWrap->IsValidObject()) return NS_ERROR_INVALID_POINTER; if (tmpAccWrap->GetAtkObject() != aAtkObj) return NS_ERROR_FAILURE; return NS_OK; } // Check if aAtkObj is a valid MaiAtkObject, and return the nsAccessibleWrap // for it. nsAccessibleWrap *GetAccessibleWrap(AtkObject *aAtkObj) { NS_ENSURE_TRUE(MAI_IS_ATK_OBJECT(aAtkObj), nsnull); nsAccessibleWrap * tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap; NS_ENSURE_TRUE(tmpAccWrap != nsnull, nsnull); NS_ENSURE_TRUE(tmpAccWrap->GetAtkObject() == aAtkObj, nsnull); return tmpAccWrap; }