Back to index

lightning-sunbird  0.9+nobinonly
nsAccessibleWrap.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  *
00008  * The contents of this file are subject to the Mozilla Public
00009  * License Version 1.1 (the "License"); you may not use this file
00010  * except in compliance with the License. You may obtain a copy of
00011  * the License at http://www.mozilla.org/MPL/
00012  *
00013  * Software distributed under the License is distributed on an "AS
00014  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00015  * implied. See the License for the specific language governing
00016  * rights and limitations under the License.
00017  *
00018  * The Original Code is mozilla.org code.
00019  *
00020  * The Initial Developer of the Original Code is Sun Microsystems, Inc.
00021  * Portions created by Sun Microsystems are Copyright (C) 2002 Sun
00022  * Microsystems, Inc. All Rights Reserved.
00023  *
00024  * Original Author: Bolian Yin (bolian.yin@sun.com)
00025  *
00026  * Contributor(s): John Sun (john.sun@sun.com)
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the NPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the NPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsMai.h"
00043 #include "nsAccessibleWrap.h"
00044 #include "nsAppRootAccessible.h"
00045 #include "nsString.h"
00046 #include "prprf.h"
00047 
00048 #include "nsMaiInterfaceComponent.h"
00049 #include "nsMaiInterfaceAction.h"
00050 #include "nsMaiInterfaceText.h"
00051 #include "nsMaiInterfaceEditableText.h"
00052 #include "nsMaiInterfaceSelection.h"
00053 #include "nsMaiInterfaceValue.h"
00054 #include "nsMaiInterfaceHypertext.h"
00055 #include "nsMaiInterfaceTable.h"
00056 
00057 /* MaiAtkObject */
00058 
00059 enum {
00060   ACTIVATE,
00061   CREATE,
00062   DEACTIVATE,
00063   DESTROY,
00064   MAXIMIZE,
00065   MINIMIZE,
00066   RESIZE,
00067   RESTORE,
00068   LAST_SIGNAL
00069 };
00070 
00074 struct MaiAtkObject
00075 {
00076     AtkObject parent;
00077     /*
00078      * The nsAccessibleWrap whose properties and features are exported
00079      * via this object instance.
00080      */
00081     nsAccessibleWrap *accWrap;
00082 };
00083 
00084 struct MaiAtkObjectClass
00085 {
00086     AtkObjectClass parent_class;
00087 };
00088 
00089 static guint mai_atk_object_signals [LAST_SIGNAL] = { 0, };
00090 
00091 #ifdef MAI_LOGGING
00092 PRInt32 sMaiAtkObjCreated = 0;
00093 PRInt32 sMaiAtkObjDeleted = 0;
00094 #endif
00095 
00096 G_BEGIN_DECLS
00097 /* callbacks for MaiAtkObject */
00098 static void classInitCB(AtkObjectClass *aClass);
00099 static void initializeCB(AtkObject *aAtkObj, gpointer aData);
00100 static void finalizeCB(GObject *aObj);
00101 
00102 /* callbacks for AtkObject virtual functions */
00103 static const gchar*        getNameCB (AtkObject *aAtkObj);
00104 static const gchar*        getDescriptionCB (AtkObject *aAtkObj);
00105 static AtkRole             getRoleCB(AtkObject *aAtkObj);
00106 static AtkObject*          getParentCB(AtkObject *aAtkObj);
00107 static gint                getChildCountCB(AtkObject *aAtkObj);
00108 static AtkObject*          refChildCB(AtkObject *aAtkObj, gint aChildIndex);
00109 static gint                getIndexInParentCB(AtkObject *aAtkObj);
00110 static AtkStateSet*        refStateSetCB(AtkObject *aAtkObj);
00111 static AtkRelationSet*     refRelationSetCB(AtkObject *aAtkObj);
00112 
00113 /* the missing atkobject virtual functions */
00114 /*
00115   static AtkLayer            getLayerCB(AtkObject *aAtkObj);
00116   static gint                getMdiZorderCB(AtkObject *aAtkObj);
00117   static void                SetNameCB(AtkObject *aAtkObj,
00118   const gchar *name);
00119   static void                SetDescriptionCB(AtkObject *aAtkObj,
00120   const gchar *description);
00121   static void                SetParentCB(AtkObject *aAtkObj,
00122   AtkObject *parent);
00123   static void                SetRoleCB(AtkObject *aAtkObj,
00124   AtkRole role);
00125   static guint               ConnectPropertyChangeHandlerCB(
00126   AtkObject  *aObj,
00127   AtkPropertyChangeHandler *handler);
00128   static void                RemovePropertyChangeHandlerCB(
00129   AtkObject *aAtkObj,
00130   guint handler_id);
00131   static void                InitializeCB(AtkObject *aAtkObj,
00132   gpointer data);
00133   static void                ChildrenChangedCB(AtkObject *aAtkObj,
00134   guint change_index,
00135   gpointer changed_child);
00136   static void                FocusEventCB(AtkObject *aAtkObj,
00137   gboolean focus_in);
00138   static void                PropertyChangeCB(AtkObject *aAtkObj,
00139   AtkPropertyValues *values);
00140   static void                StateChangeCB(AtkObject *aAtkObj,
00141   const gchar *name,
00142   gboolean state_set);
00143   static void                VisibleDataChangedCB(AtkObject *aAtkObj);
00144 */
00145 G_END_DECLS
00146 
00147 static GType GetMaiAtkType(const PRUint32 & interfaceCount,
00148                            MaiInterface **interfaces);
00149 static const char * GetUniqueMaiAtkTypeName(MaiInterface **interfaces);
00150 
00151 static gpointer parent_class = NULL;
00152 
00153 GType
00154 mai_atk_object_get_type(void)
00155 {
00156     static GType type = 0;
00157 
00158     if (!type) {
00159         static const GTypeInfo tinfo = {
00160             sizeof(MaiAtkObjectClass),
00161             (GBaseInitFunc)NULL,
00162             (GBaseFinalizeFunc)NULL,
00163             (GClassInitFunc)classInitCB,
00164             (GClassFinalizeFunc)NULL,
00165             NULL, /* class data */
00166             sizeof(MaiAtkObject), /* instance size */
00167             0, /* nb preallocs */
00168             (GInstanceInitFunc)NULL,
00169             NULL /* value table */
00170         };
00171 
00172         type = g_type_register_static(ATK_TYPE_OBJECT,
00173                                       "MaiAtkObject", &tinfo, GTypeFlags(0));
00174     }
00175     return type;
00176 }
00177 
00178 #ifdef MAI_LOGGING
00179 PRInt32 nsAccessibleWrap::mAccWrapCreated = 0;
00180 PRInt32 nsAccessibleWrap::mAccWrapDeleted = 0;
00181 #endif
00182 
00183 nsAccessibleWrap::nsAccessibleWrap(nsIDOMNode* aNode,
00184                                    nsIWeakReference *aShell)
00185     : nsAccessible(aNode, aShell),
00186       mMaiAtkObject(nsnull),
00187       mInterfaces(nsnull),
00188       mInterfaceCount(0)
00189 {
00190 #ifdef MAI_LOGGING
00191     ++mAccWrapCreated;
00192 #endif
00193     MAI_LOG_DEBUG(("==nsAccessibleWrap creating: this=%p,total=%d left=%d\n",
00194                    (void*)this, mAccWrapCreated,
00195                   (mAccWrapCreated-mAccWrapDeleted)));
00196 }
00197 
00198 nsAccessibleWrap::~nsAccessibleWrap()
00199 {
00200 
00201 #ifdef MAI_LOGGING
00202     ++mAccWrapDeleted;
00203 #endif
00204     MAI_LOG_DEBUG(("==nsAccessibleWrap deleting: this=%p,total=%d left=%d\n",
00205                    (void*)this, mAccWrapDeleted,
00206                    (mAccWrapCreated-mAccWrapDeleted)));
00207 
00208     if (mMaiAtkObject) {
00209         MAI_ATK_OBJECT(mMaiAtkObject)->accWrap = nsnull;
00210         g_object_unref(mMaiAtkObject);
00211     }
00212     if (mInterfaces) {
00213         for (int index = 0; index < MAI_INTERFACE_NUM; ++index)
00214             delete mInterfaces[index];
00215         delete [] mInterfaces;
00216     }
00217 }
00218 
00219 NS_IMETHODIMP nsAccessibleWrap::GetExtState(PRUint32 *aState)
00220 {
00221     PRUint32 state;
00222     nsAccessible::GetState(&state);
00223     if (!(state & STATE_INVISIBLE))
00224       *aState |= EXT_STATE_SHOWING;
00225     return NS_OK;
00226 }
00227 
00228 NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible)
00229 {
00230     *aOutAccessible = nsnull;
00231 
00232     if (!mMaiAtkObject) {
00233         CreateMaiInterfaces();
00234         GType type = GetMaiAtkType(mInterfaceCount, mInterfaces);
00235         NS_ENSURE_TRUE(type, NS_ERROR_FAILURE);
00236         mMaiAtkObject =
00237             NS_REINTERPRET_CAST(AtkObject *,
00238                                 g_object_new(type, NULL));
00239         NS_ENSURE_TRUE(mMaiAtkObject, NS_ERROR_OUT_OF_MEMORY);
00240 
00241         atk_object_initialize(mMaiAtkObject, this);
00242         mMaiAtkObject->role = ATK_ROLE_INVALID;
00243         mMaiAtkObject->layer = ATK_LAYER_INVALID;
00244     }
00245 
00246     *aOutAccessible = mMaiAtkObject;
00247     return NS_OK;
00248 }
00249 
00250 AtkObject *
00251 nsAccessibleWrap::GetAtkObject(void)
00252 {
00253     void *atkObj = nsnull;
00254     GetNativeInterface(&atkObj);
00255     return NS_STATIC_CAST(AtkObject *, atkObj);
00256 }
00257 
00258 /* private */
00259 nsresult
00260 nsAccessibleWrap::CreateMaiInterfaces(void)
00261 {
00262     typedef MaiInterface * MaiInterfacePointer;
00263     if (!mInterfaces) {
00264         mInterfaces = new MaiInterfacePointer[MAI_INTERFACE_NUM];
00265         for (PRUint16 index = 0; index < MAI_INTERFACE_NUM; ++index) {
00266             mInterfaces[index] = nsnull;
00267         }
00268         NS_ENSURE_TRUE(mInterfaces, NS_ERROR_OUT_OF_MEMORY);
00269     }
00270     // Add Interfaces for each nsIAccessible.ext interfaces
00271 
00272     nsresult rv;
00273 
00274     // the Component interface are supported by all nsIAccessible
00275     MaiInterfaceComponent *maiInterfaceComponent =
00276         new MaiInterfaceComponent(this);
00277     NS_ENSURE_TRUE(maiInterfaceComponent, NS_ERROR_OUT_OF_MEMORY);
00278     rv = AddMaiInterface(maiInterfaceComponent);
00279     NS_ENSURE_SUCCESS(rv, rv);
00280 
00281     // Add Action interface if the action count is more than zero.
00282     PRUint8 actionCount = 0;
00283     rv = GetNumActions(&actionCount);
00284     if (NS_SUCCEEDED(rv) && actionCount > 0) {
00285         MaiInterfaceAction *maiInterfaceAction = new MaiInterfaceAction(this);
00286         NS_ENSURE_TRUE(maiInterfaceAction, NS_ERROR_OUT_OF_MEMORY);
00287         rv = AddMaiInterface(maiInterfaceAction);
00288         NS_ENSURE_SUCCESS(rv, rv);
00289     }
00290 
00291 
00292     PRUint32 accRole;
00293     rv = GetRole(&accRole);
00294 
00295     if (accRole != nsIAccessible::ROLE_HTML_CONTAINER) {
00296         //nsIAccessibleText
00297         nsCOMPtr<nsIAccessibleText> accessInterfaceText;
00298         QueryInterface(NS_GET_IID(nsIAccessibleText),
00299                        getter_AddRefs(accessInterfaceText));
00300         if (accessInterfaceText) {
00301             MaiInterfaceText *maiInterfaceText = new MaiInterfaceText(this);
00302             NS_ENSURE_TRUE(maiInterfaceText, NS_ERROR_OUT_OF_MEMORY);
00303             rv = AddMaiInterface(maiInterfaceText);
00304             NS_ENSURE_SUCCESS(rv, rv);
00305         }
00306 
00307         //nsIAccessibleEditableText
00308         nsCOMPtr<nsIAccessibleEditableText> accessInterfaceEditableText;
00309         QueryInterface(NS_GET_IID(nsIAccessibleEditableText),
00310                        getter_AddRefs(accessInterfaceEditableText));
00311         if (accessInterfaceEditableText) {
00312             MaiInterfaceEditableText *maiInterfaceEditableText =
00313                 new MaiInterfaceEditableText(this);
00314             NS_ENSURE_TRUE(maiInterfaceEditableText, NS_ERROR_OUT_OF_MEMORY);
00315             rv = AddMaiInterface(maiInterfaceEditableText);
00316             NS_ENSURE_SUCCESS(rv, rv);
00317         }
00318     }
00319 
00320     //nsIAccessibleSelection
00321     nsCOMPtr<nsIAccessibleSelectable> accessInterfaceSelection;
00322     QueryInterface(NS_GET_IID(nsIAccessibleSelectable),
00323                    getter_AddRefs(accessInterfaceSelection));
00324     if (accessInterfaceSelection) {
00325         MaiInterfaceSelection *maiInterfaceSelection =
00326             new MaiInterfaceSelection(this);
00327         NS_ENSURE_TRUE(maiInterfaceSelection, NS_ERROR_OUT_OF_MEMORY);
00328         rv = AddMaiInterface(maiInterfaceSelection);
00329         NS_ENSURE_SUCCESS(rv, rv);
00330     }
00331 
00332     //nsIAccessibleValue
00333     nsCOMPtr<nsIAccessibleValue> accessInterfaceValue;
00334     QueryInterface(NS_GET_IID(nsIAccessibleValue),
00335                    getter_AddRefs(accessInterfaceValue));
00336     if (accessInterfaceValue) {
00337         MaiInterfaceValue *maiInterfaceValue = new MaiInterfaceValue(this);
00338         NS_ENSURE_TRUE(maiInterfaceValue, NS_ERROR_OUT_OF_MEMORY);
00339         rv = AddMaiInterface(maiInterfaceValue);
00340         NS_ENSURE_SUCCESS(rv, rv);
00341     }
00342 
00343     //nsIAccessibleHypertext
00344     PRInt32 linkCount = 0;
00345     nsCOMPtr<nsIAccessibleHyperText> accessInterfaceHypertext;
00346     QueryInterface(NS_GET_IID(nsIAccessibleHyperText),
00347                    getter_AddRefs(accessInterfaceHypertext));
00348     if (accessInterfaceHypertext) {
00349         rv = accessInterfaceHypertext->GetLinks(&linkCount);
00350         if (NS_SUCCEEDED(rv) && (linkCount > 0)) {
00351             MaiInterfaceHypertext *maiInterfaceHypertext =
00352                 new MaiInterfaceHypertext(this, mWeakShell);
00353             NS_ENSURE_TRUE(maiInterfaceHypertext, NS_ERROR_OUT_OF_MEMORY);
00354             rv = AddMaiInterface(maiInterfaceHypertext);
00355             NS_ENSURE_SUCCESS(rv, rv);
00356         }
00357     }
00358 
00359     //nsIAccessibleTable
00360     if (accRole == nsIAccessible::ROLE_TREE_TABLE) {
00361       // In most cases, html table is used as container to arrange the webpage,
00362       // not to represent a "real" table with practical colum, colum heaer, row.
00363       // So, only add maiInterfaceTable for XUL table.
00364       nsCOMPtr<nsIAccessibleTable> accessInterfaceTable;
00365       QueryInterface(NS_GET_IID(nsIAccessibleTable),
00366                      getter_AddRefs(accessInterfaceTable));
00367       if (accessInterfaceTable) {
00368           MaiInterfaceTable *maiInterfaceTable = new MaiInterfaceTable(this);
00369           NS_ENSURE_TRUE(maiInterfaceTable, NS_ERROR_OUT_OF_MEMORY);
00370           rv = AddMaiInterface(maiInterfaceTable);
00371           NS_ENSURE_SUCCESS(rv, rv);
00372       }
00373     }
00374 
00375     return rv;
00376 }
00377 
00378 nsresult
00379 nsAccessibleWrap::AddMaiInterface(MaiInterface *aMaiIface)
00380 {
00381     NS_ENSURE_ARG_POINTER(aMaiIface);
00382     MaiInterfaceType aMaiIfaceType = aMaiIface->GetType();
00383 
00384     if ((aMaiIfaceType <= MAI_INTERFACE_INVALID) ||
00385         (aMaiIfaceType >= MAI_INTERFACE_NUM))
00386         return NS_ERROR_FAILURE;
00387 
00388     // if same type of If has been added, release previous one
00389     if (mInterfaces[aMaiIfaceType]) {
00390         delete mInterfaces[aMaiIfaceType];
00391     }
00392     mInterfaces[aMaiIfaceType] = aMaiIface;
00393     mInterfaceCount++;
00394     return NS_OK;
00395 }
00396 MaiInterface *
00397 nsAccessibleWrap::GetMaiInterface(PRInt16 aIfaceType)
00398 {
00399     NS_ENSURE_TRUE(aIfaceType > MAI_INTERFACE_INVALID, nsnull);
00400     NS_ENSURE_TRUE(aIfaceType < MAI_INTERFACE_NUM, nsnull);
00401     return mInterfaces[aIfaceType];
00402 }
00403 
00404 static GType
00405 GetMaiAtkType(const PRUint32 & interfaceCount, MaiInterface **interfaces)
00406 {
00407     GType type;
00408     static const GTypeInfo tinfo = {
00409         sizeof(MaiAtkObjectClass),
00410         (GBaseInitFunc) NULL,
00411         (GBaseFinalizeFunc) NULL,
00412         (GClassInitFunc) NULL,
00413         (GClassFinalizeFunc) NULL,
00414         NULL, /* class data */
00415         sizeof(MaiAtkObject), /* instance size */
00416         0, /* nb preallocs */
00417         (GInstanceInitFunc) NULL,
00418         NULL /* value table */
00419     };
00420 
00421     if (interfaceCount == 0)
00422         return MAI_TYPE_ATK_OBJECT;
00423 
00424     /*
00425      * The members we used to register a GType are MaiInterface::GetAtkType()
00426      * and MaiInterface::GetInterfaceInfo(), which is the same with different
00427      * MaiInterface objects. So we can reuse the registered GType when having
00428      * the same MaiInterface types.
00429      */
00430     const char *atkTypeName = GetUniqueMaiAtkTypeName(interfaces);
00431     type = g_type_from_name(atkTypeName);
00432     if (type) {
00433         return type;
00434     }
00435 
00436     /*
00437      * gobject limits the number of types that can directly derive from any
00438      * given object type to 4095.
00439      */
00440     static PRUint16 typeRegCount = 0;
00441     if (typeRegCount++ < 4095) {
00442         type = g_type_register_static(MAI_TYPE_ATK_OBJECT,
00443                                       atkTypeName,
00444                                       &tinfo, GTypeFlags(0));
00445     }
00446     else {
00447         return 0;
00448     }
00449 
00450     for (int index = 0; index < MAI_INTERFACE_NUM; index++) {
00451         if (!interfaces[index])
00452             continue;
00453         g_type_add_interface_static(type,
00454                                     interfaces[index]->GetAtkType(),
00455                                     interfaces[index]->GetInterfaceInfo());
00456     }
00457     return type;
00458 }
00459 
00460 static const char *
00461 GetUniqueMaiAtkTypeName(MaiInterface **interfaces)
00462 {
00463 #define MAI_ATK_TYPE_NAME_LEN (30)     /* 10+sizeof(PRUint16)*8/4+1 < 30 */
00464 
00465     PRUint16 atkTypeNameId = 0;
00466     static gchar namePrefix[] = "MaiAtkType";   /* size = 10 */
00467     static gchar name[MAI_ATK_TYPE_NAME_LEN + 1];
00468 
00469     for (int index = 0; index < MAI_INTERFACE_NUM; index++) {
00470         if (interfaces[index])
00471             atkTypeNameId |= 1 << index;
00472     }
00473     PR_snprintf(name, MAI_ATK_TYPE_NAME_LEN, "%s%x", namePrefix, atkTypeNameId);
00474     name[MAI_ATK_TYPE_NAME_LEN] = '\0';
00475 
00476     MAI_LOG_DEBUG(("MaiWidget::LastedTypeName=%s\n", name));
00477 
00478     return name;
00479 }
00480 
00481 /******************************************************************************
00482 The following nsIAccessible states aren't translated, just ignored.
00483   STATE_MIXED:         For a three-state check box.
00484   STATE_READONLY:      The object is designated read-only.
00485   STATE_HOTTRACKED:    Means its appearance has changed to indicate mouse
00486                        over it.
00487   STATE_FLOATING:      Not supported yet.
00488   STATE_MARQUEED:      Indicate scrolling or moving text or graphics.
00489   STATE_ANIMATED:
00490   STATE_OFFSCREEN:     Has no on-screen representation.
00491   STATE_MOVEABLE:
00492   STATE_SELFVOICING:   The object has self-TTS.
00493   STATE_LINKED:        The object is formatted as a hyperlink.
00494   STATE_TRAVERSE:      The object is a hyperlink that has been visited.
00495   STATE_EXTSELECTABLE: Indicates that an object extends its selectioin.
00496   STATE_ALERT_LOW:     Not supported yet.
00497   STATE_ALERT_MEDIUM:  Not supported yet.
00498   STATE_ALERT_HIGH:    Not supported yet.
00499   STATE_PROTECTED:     The object is a password-protected edit control.
00500   STATE_HASPOPUP:      Object displays a pop-up menu or window when invoked.
00501 
00502 Returned AtkStatusSet never contain the following AtkStates.
00503   ATK_STATE_ARMED:     Indicates that the object is armed.
00504   ATK_STATE_DEFUNCT:   Indicates the user interface object corresponding to
00505                        thus object no longer exists.
00506   ATK_STATE_HORIZONTAL:Indicates the orientation of this object is horizontal.
00507   ATK_STATE_ICONIFIED:
00508   ATK_STATE_OPAQUE:     Indicates the object paints every pixel within its
00509                         rectangular region
00510   ATK_STATE_STALE:      The index associated with this object has changed since
00511                         the user accessed the object
00512 ******************************************************************************/
00513 
00514 void
00515 nsAccessibleWrap::TranslateStates(PRUint32 aState, PRUint32 aExtState, void *aAtkStateSet)
00516 {
00517     if (!aAtkStateSet)
00518         return;
00519     AtkStateSet *state_set = NS_STATIC_CAST(AtkStateSet *, aAtkStateSet);
00520 
00521     if (aState & nsIAccessible::STATE_SELECTED)
00522         atk_state_set_add_state (state_set, ATK_STATE_SELECTED);
00523 
00524     if (aState & nsIAccessible::STATE_FOCUSED)
00525         atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
00526 
00527     if (aState & nsIAccessible::STATE_PRESSED)
00528         atk_state_set_add_state (state_set, ATK_STATE_PRESSED);
00529 
00530     if (aState & nsIAccessible::STATE_CHECKED)
00531         atk_state_set_add_state (state_set, ATK_STATE_CHECKED);
00532 
00533     if (aState & nsIAccessible::STATE_EXPANDED)
00534         atk_state_set_add_state (state_set, ATK_STATE_EXPANDED);
00535 
00536     if (aState & nsIAccessible::STATE_COLLAPSED)
00537         atk_state_set_add_state (state_set, ATK_STATE_EXPANDABLE);
00538                    
00539     // The control can't accept input at this time
00540     if (aState & nsIAccessible::STATE_BUSY)
00541         atk_state_set_add_state (state_set, ATK_STATE_BUSY);
00542 
00543     if (aState & nsIAccessible::STATE_FOCUSABLE)
00544         atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
00545 
00546     if (!(aState & nsIAccessible::STATE_INVISIBLE))
00547         atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
00548 
00549     if (aState & nsIAccessible::STATE_SELECTABLE)
00550         atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
00551 
00552     if (aState & nsIAccessible::STATE_SIZEABLE)
00553         atk_state_set_add_state (state_set, ATK_STATE_RESIZABLE);
00554 
00555     if (aState & nsIAccessible::STATE_MULTISELECTABLE)
00556         atk_state_set_add_state (state_set, ATK_STATE_MULTISELECTABLE);
00557 
00558     if (!(aState & nsIAccessible::STATE_UNAVAILABLE)) {
00559         atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
00560         atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
00561     }
00562 
00563     if (aState & nsIAccessible::STATE_INVALID)
00564         atk_state_set_add_state (state_set, ATK_STATE_INVALID);
00565 
00566 #ifdef ATK_STATE_DEFAULT
00567     if (aState & nsIAccessible::STATE_DEFAULT)
00568         atk_state_set_add_state (state_set, ATK_STATE_DEFAULT);
00569 #endif
00570 
00571 #ifdef ATK_STATE_REQUIRED
00572     if (aState & nsIAccessible::STATE_REQUIRED)
00573         atk_state_set_add_state (state_set, ATK_STATE_REQUIRED);
00574 #endif
00575 
00576     // The following state is
00577     // Extended state flags (for now non-MSAA, for Java and Gnome/ATK support)
00578     if (aExtState & nsIAccessible::EXT_STATE_ACTIVE)
00579         atk_state_set_add_state (state_set, ATK_STATE_ACTIVE);
00580 
00581     if (aExtState & nsIAccessible::EXT_STATE_EXPANDABLE)
00582         atk_state_set_add_state (state_set, ATK_STATE_EXPANDABLE);
00583 
00584     if (aExtState & nsIAccessible::EXT_STATE_MODAL)
00585         atk_state_set_add_state (state_set, ATK_STATE_MODAL);
00586 
00587     if (aExtState & nsIAccessible::EXT_STATE_MULTI_LINE)
00588         atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE);
00589 
00590     if (aExtState & nsIAccessible::EXT_STATE_SENSITIVE)
00591         atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
00592 
00593     if (aExtState & nsIAccessible::EXT_STATE_SHOWING)
00594         atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
00595 
00596     if (aExtState & nsIAccessible::EXT_STATE_SINGLE_LINE)
00597         atk_state_set_add_state (state_set, ATK_STATE_SINGLE_LINE);
00598 
00599     if (aExtState & nsIAccessible::EXT_STATE_TRANSIENT)
00600         atk_state_set_add_state (state_set, ATK_STATE_TRANSIENT);
00601 
00602     if (aExtState & nsIAccessible::EXT_STATE_VERTICAL)
00603         atk_state_set_add_state (state_set, ATK_STATE_VERTICAL);
00604 
00605     if (aExtState & nsIAccessible::EXT_STATE_EDITABLE)
00606         atk_state_set_add_state (state_set, ATK_STATE_EDITABLE);
00607 }
00608 
00609 PRBool nsAccessibleWrap::IsValidObject()
00610 {
00611     // to ensure we are not shut down
00612     return (mDOMNode != nsnull);
00613 }
00614 
00615 /* static functions for ATK callbacks */
00616 void
00617 classInitCB(AtkObjectClass *aClass)
00618 {
00619     GObjectClass *gobject_class = G_OBJECT_CLASS(aClass);
00620 
00621     parent_class = g_type_class_peek_parent(aClass);
00622 
00623     aClass->get_name = getNameCB;
00624     aClass->get_description = getDescriptionCB;
00625     aClass->get_parent = getParentCB;
00626     aClass->get_n_children = getChildCountCB;
00627     aClass->ref_child = refChildCB;
00628     aClass->get_index_in_parent = getIndexInParentCB;
00629     aClass->get_role = getRoleCB;
00630     aClass->ref_state_set = refStateSetCB;
00631     aClass->ref_relation_set = refRelationSetCB;
00632 
00633     aClass->initialize = initializeCB;
00634 
00635     gobject_class->finalize = finalizeCB;
00636 
00637     mai_atk_object_signals [ACTIVATE] =
00638     g_signal_new ("activate",
00639                   MAI_TYPE_ATK_OBJECT,
00640                   G_SIGNAL_RUN_LAST,
00641                   0, /* default signal handler */
00642                   NULL, NULL,
00643                   g_cclosure_marshal_VOID__VOID,
00644                   G_TYPE_NONE, 0);
00645     mai_atk_object_signals [CREATE] =
00646     g_signal_new ("create",
00647                   MAI_TYPE_ATK_OBJECT,
00648                   G_SIGNAL_RUN_LAST,
00649                   0, /* default signal handler */
00650                   NULL, NULL,
00651                   g_cclosure_marshal_VOID__VOID,
00652                   G_TYPE_NONE, 0);
00653     mai_atk_object_signals [DEACTIVATE] =
00654     g_signal_new ("deactivate",
00655                   MAI_TYPE_ATK_OBJECT,
00656                   G_SIGNAL_RUN_LAST,
00657                   0, /* default signal handler */
00658                   NULL, NULL,
00659                   g_cclosure_marshal_VOID__VOID,
00660                   G_TYPE_NONE, 0);
00661     mai_atk_object_signals [DESTROY] =
00662     g_signal_new ("destroy",
00663                   MAI_TYPE_ATK_OBJECT,
00664                   G_SIGNAL_RUN_LAST,
00665                   0, /* default signal handler */
00666                   NULL, NULL,
00667                   g_cclosure_marshal_VOID__VOID,
00668                   G_TYPE_NONE, 0);
00669     mai_atk_object_signals [MAXIMIZE] =
00670     g_signal_new ("maximize",
00671                   MAI_TYPE_ATK_OBJECT,
00672                   G_SIGNAL_RUN_LAST,
00673                   0, /* default signal handler */
00674                   NULL, NULL,
00675                   g_cclosure_marshal_VOID__VOID,
00676                   G_TYPE_NONE, 0);
00677     mai_atk_object_signals [MINIMIZE] =
00678     g_signal_new ("minimize",
00679                   MAI_TYPE_ATK_OBJECT,
00680                   G_SIGNAL_RUN_LAST,
00681                   0, /* default signal handler */
00682                   NULL, NULL,
00683                   g_cclosure_marshal_VOID__VOID,
00684                   G_TYPE_NONE, 0);
00685     mai_atk_object_signals [RESIZE] =
00686     g_signal_new ("resize",
00687                   MAI_TYPE_ATK_OBJECT,
00688                   G_SIGNAL_RUN_LAST,
00689                   0, /* default signal handler */
00690                   NULL, NULL,
00691                   g_cclosure_marshal_VOID__VOID,
00692                   G_TYPE_NONE, 0);
00693     mai_atk_object_signals [RESTORE] =
00694     g_signal_new ("restore",
00695                   MAI_TYPE_ATK_OBJECT,
00696                   G_SIGNAL_RUN_LAST,
00697                   0, /* default signal handler */
00698                   NULL, NULL,
00699                   g_cclosure_marshal_VOID__VOID,
00700                   G_TYPE_NONE, 0);
00701 
00702 }
00703 
00704 void
00705 initializeCB(AtkObject *aAtkObj, gpointer aData)
00706 {
00707     NS_ASSERTION((MAI_IS_ATK_OBJECT(aAtkObj)), "Invalid AtkObject");
00708     NS_ASSERTION(aData, "Invalid Data to init AtkObject");
00709     if (!aAtkObj || !aData)
00710         return;
00711 
00712     /* call parent init function */
00713     /* AtkObjectClass has not a "initialize" function now,
00714      * maybe it has later
00715      */
00716 
00717     if (ATK_OBJECT_CLASS(parent_class)->initialize)
00718         ATK_OBJECT_CLASS(parent_class)->initialize(aAtkObj, aData);
00719 
00720     /* initialize object */
00721     MAI_ATK_OBJECT(aAtkObj)->accWrap =
00722         NS_STATIC_CAST(nsAccessibleWrap*, aData);
00723 
00724 #ifdef MAI_LOGGING
00725     ++sMaiAtkObjCreated;
00726 #endif
00727     MAI_LOG_DEBUG(("MaiAtkObj Create obj=%p for AccWrap=%p, all=%d, left=%d\n",
00728                    (void*)aAtkObj, (void*)aData, sMaiAtkObjCreated,
00729                    (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
00730 }
00731 
00732 void
00733 finalizeCB(GObject *aObj)
00734 {
00735     if (!MAI_IS_ATK_OBJECT(aObj))
00736         return;
00737     NS_ASSERTION(MAI_ATK_OBJECT(aObj)->accWrap == nsnull, "AccWrap NOT null");
00738 
00739 #ifdef MAI_LOGGING
00740     ++sMaiAtkObjDeleted;
00741 #endif
00742     MAI_LOG_DEBUG(("MaiAtkObj Delete obj=%p, all=%d, left=%d\n",
00743                    (void*)aObj, sMaiAtkObjCreated,
00744                    (sMaiAtkObjCreated-sMaiAtkObjDeleted)));
00745 
00746     // call parent finalize function
00747     // finalize of GObjectClass will unref the accessible parent if has
00748     if (G_OBJECT_CLASS (parent_class)->finalize)
00749         G_OBJECT_CLASS (parent_class)->finalize(aObj);
00750 }
00751 
00752 const gchar *
00753 getNameCB(AtkObject *aAtkObj)
00754 {
00755     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull);
00756 
00757     nsAutoString uniName;
00758 
00759     nsAccessibleWrap *accWrap =
00760         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00761 
00762     /* nsIAccessible is responsible for the non-NULL name */
00763     nsresult rv = accWrap->GetName(uniName);
00764     NS_ENSURE_SUCCESS(rv, nsnull);
00765 
00766     if (uniName.Length() > 0) {
00767         NS_ConvertUTF8toUCS2 objName(aAtkObj->name);
00768         if (!uniName.Equals(objName)) {
00769             atk_object_set_name(aAtkObj,
00770                                 NS_ConvertUCS2toUTF8(uniName).get());
00771         }
00772     }
00773     return aAtkObj->name;
00774 }
00775 
00776 const gchar *
00777 getDescriptionCB(AtkObject *aAtkObj)
00778 {
00779     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull);
00780 
00781     if (!aAtkObj->description) {
00782         gint len;
00783         nsAutoString uniDesc;
00784 
00785         nsAccessibleWrap *accWrap =
00786             NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00787 
00788         /* nsIAccessible is responsible for the non-NULL description */
00789         nsresult rv = accWrap->GetDescription(uniDesc);
00790         NS_ENSURE_SUCCESS(rv, nsnull);
00791         len = uniDesc.Length();
00792         if (len > 0) {
00793             atk_object_set_description(aAtkObj,
00794                                        NS_ConvertUCS2toUTF8(uniDesc).get());
00795         }
00796     }
00797     return aAtkObj->description;
00798 }
00799 
00800 AtkRole
00801 getRoleCB(AtkObject *aAtkObj)
00802 {
00803     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), ATK_ROLE_INVALID);
00804 
00805     if (aAtkObj->role == ATK_ROLE_INVALID) {
00806         nsAccessibleWrap *accWrap =
00807             NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00808 
00809         PRUint32 accRole;
00810         nsresult rv = accWrap->GetFinalRole(&accRole);
00811         NS_ENSURE_SUCCESS(rv, ATK_ROLE_INVALID);
00812 
00813         //the cross-platform Accessible object returns the same value for
00814         //both "ROLE_MENUITEM" and "ROLE_MENUPOPUP"
00815         if (accRole == nsIAccessible::ROLE_MENUITEM) {
00816             PRInt32 childCount = 0;
00817             accWrap->GetChildCount(&childCount);
00818             if (childCount > 0)
00819                 accRole = nsIAccessible::ROLE_MENUPOPUP;
00820         }
00821         else if (accRole == nsIAccessible::ROLE_LINK) {
00822             //ATK doesn't have role-link now
00823             //register it on runtime
00824             static AtkRole linkRole = (AtkRole)0;
00825             if (linkRole == 0) {
00826                 linkRole = atk_role_register("hyper link");
00827             }
00828             accRole = linkRole;
00829         }
00830 #ifndef ATK_ROLE_AUTOCOMPLETE
00831         else if (accRole == nsIAccessible::ROLE_AUTOCOMPLETE) {
00832                      accRole = ATK_ROLE_COMBO_BOX;
00833               }
00834 #endif
00835 #ifndef ATK_ROLE_CAPTION
00836         else if (accRole == nsIAccessible::ROLE_CAPTION) {
00837                      accRole = ATK_ROLE_LABEL;
00838               }
00839 #endif
00840         aAtkObj->role = NS_STATIC_CAST(AtkRole, accRole);
00841     }
00842     return aAtkObj->role;
00843 }
00844 
00845 AtkObject *
00846 getParentCB(AtkObject *aAtkObj)
00847 {
00848     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull);
00849     nsAccessibleWrap *accWrap =
00850         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00851 
00852     nsCOMPtr<nsIAccessible> accParent;
00853     nsresult rv = accWrap->GetParent(getter_AddRefs(accParent));
00854     if (NS_FAILED(rv) || !accParent)
00855         return nsnull;
00856     nsIAccessible *tmpParent = accParent;
00857     nsAccessibleWrap *accWrapParent = NS_STATIC_CAST(nsAccessibleWrap *,
00858                                                      tmpParent);
00859 
00860     AtkObject *parentAtkObj = accWrapParent->GetAtkObject();
00861     if (parentAtkObj && !aAtkObj->accessible_parent) {
00862         atk_object_set_parent(aAtkObj, parentAtkObj);
00863     }
00864     return parentAtkObj;
00865 }
00866 
00867 gint
00868 getChildCountCB(AtkObject *aAtkObj)
00869 {
00870     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), 0);
00871     nsAccessibleWrap *accWrap =
00872         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00873 
00874     PRInt32 count = 0;
00875     accWrap->GetChildCount(&count);
00876     return count;
00877 }
00878 
00879 AtkObject *
00880 refChildCB(AtkObject *aAtkObj, gint aChildIndex)
00881 {
00882     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), nsnull);
00883     nsAccessibleWrap *accWrap =
00884         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00885 
00886     nsresult rv;
00887     nsCOMPtr<nsIAccessible> accChild;
00888     rv = accWrap->GetChildAt(aChildIndex, getter_AddRefs(accChild));
00889 
00890     if (NS_FAILED(rv) || !accChild)
00891         return nsnull;
00892 
00893     nsIAccessible *tmpAccChild = accChild;
00894     nsAccessibleWrap *accWrapChild =
00895         NS_STATIC_CAST(nsAccessibleWrap*, tmpAccChild);
00896 
00897     //this will addref parent
00898     AtkObject *childAtkObj = accWrapChild->GetAtkObject();
00899     NS_ASSERTION(childAtkObj, "Fail to get AtkObj");
00900     if (!childAtkObj)
00901         return nsnull;
00902     atk_object_set_parent(childAtkObj,
00903                           accWrap->GetAtkObject());
00904     g_object_ref(childAtkObj);
00905     return childAtkObj;
00906 }
00907 
00908 gint
00909 getIndexInParentCB(AtkObject *aAtkObj)
00910 {
00911     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), -1);
00912     nsAccessibleWrap *accWrap =
00913         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00914 
00915     PRInt32 currentIndex = -1;
00916     accWrap->GetIndexInParent(&currentIndex);
00917     return currentIndex;
00918 }
00919 
00920 AtkStateSet *
00921 refStateSetCB(AtkObject *aAtkObj)
00922 {
00923     AtkStateSet *state_set = nsnull;
00924     state_set = ATK_OBJECT_CLASS(parent_class)->ref_state_set(aAtkObj);
00925 
00926     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), state_set);
00927     nsAccessibleWrap *accWrap =
00928         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00929 
00930     PRUint32 accState = 0;
00931     nsresult rv = accWrap->GetFinalState(&accState);
00932     NS_ENSURE_SUCCESS(rv, state_set);
00933 
00934     PRUint32 accExtState = 0;
00935     rv = accWrap->GetExtState(&accExtState);
00936     NS_ENSURE_SUCCESS(rv, state_set);
00937 
00938     if ((accState == 0) && (accExtState == 0))
00939       return state_set;
00940 
00941     nsAccessibleWrap::TranslateStates(accState, accExtState, state_set);
00942     return state_set;
00943 }
00944 
00945 AtkRelationSet *
00946 refRelationSetCB(AtkObject *aAtkObj)
00947 {
00948     AtkRelationSet *relation_set = nsnull;
00949     relation_set = ATK_OBJECT_CLASS(parent_class)->ref_relation_set(aAtkObj);
00950 
00951     NS_ENSURE_SUCCESS(CheckMaiAtkObject(aAtkObj), relation_set);
00952     nsAccessibleWrap *accWrap =
00953         NS_REINTERPRET_CAST(MaiAtkObject*, aAtkObj)->accWrap;
00954 
00955     AtkObject *accessible_array[1];
00956     AtkRelation* relation;
00957     
00958     PRUint32 relationType[] = {nsIAccessible::RELATION_LABELLED_BY,
00959                                nsIAccessible::RELATION_LABEL_FOR,
00960                                nsIAccessible::RELATION_NODE_CHILD_OF};
00961 
00962     for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(relationType); i++) { 
00963       if (!atk_relation_set_contains(relation_set, NS_STATIC_CAST(AtkRelationType, relationType[i]))) {
00964           nsIAccessible* accRelated;
00965           nsresult rv = accWrap->GetAccessibleRelated(relationType[i], &accRelated);
00966           if (NS_SUCCEEDED(rv) && accRelated) {
00967               accessible_array[0] = NS_STATIC_CAST(nsAccessibleWrap*, accRelated)->GetAtkObject();
00968               relation = atk_relation_new(accessible_array, 1,
00969                                            NS_STATIC_CAST(AtkRelationType, relationType[i]));
00970               atk_relation_set_add(relation_set, relation);
00971           }
00972       }
00973     }
00974 
00975     return relation_set;
00976 }
00977 
00978 // Check if aAtkObj is a valid MaiAtkObject
00979 nsresult
00980 CheckMaiAtkObject(AtkObject *aAtkObj)
00981 {
00982     NS_ENSURE_ARG(MAI_IS_ATK_OBJECT(aAtkObj));
00983     nsAccessibleWrap * tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
00984     if (tmpAccWrap == nsnull)
00985         return NS_ERROR_INVALID_POINTER;
00986     if (tmpAccWrap != nsAppRootAccessible::Create() && !tmpAccWrap->IsValidObject())
00987         return NS_ERROR_INVALID_POINTER;
00988     if (tmpAccWrap->GetAtkObject() != aAtkObj)
00989         return NS_ERROR_FAILURE;
00990     return NS_OK;
00991 }
00992 
00993 // Check if aAtkObj is a valid MaiAtkObject, and return the nsAccessibleWrap
00994 // for it.
00995 nsAccessibleWrap *GetAccessibleWrap(AtkObject *aAtkObj)
00996 {
00997     NS_ENSURE_TRUE(MAI_IS_ATK_OBJECT(aAtkObj), nsnull);
00998     nsAccessibleWrap * tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
00999     NS_ENSURE_TRUE(tmpAccWrap != nsnull, nsnull);
01000     NS_ENSURE_TRUE(tmpAccWrap->GetAtkObject() == aAtkObj, nsnull);
01001     return tmpAccWrap;
01002 }