From 6f7d1e285576959da2491eb5098f93614d9f4a3d Mon Sep 17 00:00:00 2001 From: "bolian.yin%sun.com" Date: Thu, 24 Oct 2002 03:06:04 +0000 Subject: [PATCH] Bug 173848 the Root/Application object got from an event by "get_parent" is not the same with the original Root/Application Object. This is NOT for default build --- widget/src/gtk2/mai/nsMaiAppRoot.cpp | 141 +++++--------- widget/src/gtk2/mai/nsMaiAppRoot.h | 23 +-- widget/src/gtk2/mai/nsMaiCache.cpp | 202 +++++++++++++------- widget/src/gtk2/mai/nsMaiCache.h | 46 +++-- widget/src/gtk2/mai/nsMaiHyperlink.cpp | 3 +- widget/src/gtk2/mai/nsMaiInterfaceTable.cpp | 8 +- widget/src/gtk2/mai/nsMaiObject.cpp | 15 +- widget/src/gtk2/mai/nsMaiTopLevel.cpp | 176 ++++++++++------- widget/src/gtk2/mai/nsMaiTopLevel.h | 1 + widget/src/gtk2/mai/nsMaiUtil.cpp | 70 ++++--- widget/src/gtk2/mai/nsMaiUtil.h | 2 +- widget/src/gtk2/mai/nsMaiWidget.cpp | 152 ++++++++------- widget/src/gtk2/mai/nsMaiWidget.h | 2 + 13 files changed, 453 insertions(+), 388 deletions(-) diff --git a/widget/src/gtk2/mai/nsMaiAppRoot.cpp b/widget/src/gtk2/mai/nsMaiAppRoot.cpp index 1f054fe97052..1268b0945b95 100644 --- a/widget/src/gtk2/mai/nsMaiAppRoot.cpp +++ b/widget/src/gtk2/mai/nsMaiAppRoot.cpp @@ -41,15 +41,13 @@ #include "nsIAccessible.h" #include "nsCOMPtr.h" - +#include "nsMaiCache.h" #include "nsMaiAppRoot.h" MaiAppRoot::MaiAppRoot() { /* for mai root, mAccessible is always NULL */ mTopLevelList = NULL; - mMaiCache = new MaiCache(); - NS_ASSERTION(mMaiCache, "Fail to create MaiCache"); } MaiAppRoot::~MaiAppRoot() @@ -59,23 +57,23 @@ MaiAppRoot::~MaiAppRoot() if (mTopLevelList) { GList *tmp_list1, *tmp_list2; MaiTopLevel *maiTopLevel; + guint uid; tmp_list1 = tmp_list2 = mTopLevelList; mTopLevelList = NULL; +#ifdef MAI_LOGGING while (tmp_list1) { - maiTopLevel = ((TopLevelItem*)tmp_list1->data)->maiTopLevel; + uid = (guint)tmp_list1->data; + maiTopLevel = (MaiTopLevel *) MaiHashTable::Lookup(uid); + if (maiTopLevel) + MAI_LOG_DEBUG(("##toplevel=0x%x (uid=0x%x) still exist !\n", + (guint)maiTopLevel, uid)); tmp_list1 = tmp_list1->next; - - g_object_unref(maiTopLevel->GetAtkObject()); } - g_list_free(tmp_list2); - mTopLevelList = NULL; - } +#endif /* #ifdef MAI_LOGGING */ - if (mMaiCache) { - delete mMaiCache; - mMaiCache = NULL; + g_list_free(tmp_list2); } } @@ -116,107 +114,50 @@ MaiAppRoot::GetNSAccessibleUniqueID() return 1; } -gboolean +PRBool MaiAppRoot::AddMaiTopLevel(MaiTopLevel *aTopLevel) { g_return_val_if_fail(aTopLevel != NULL, FALSE); MAI_LOG_DEBUG(("MaiAppRoot: add MaiTopLevel = 0x%x", (guint)aTopLevel)); - /* if the nsIAccessible with the same UniqueID is already added, - * we only increase the count of this item in the list. - * They are same. - */ - - TopLevelItem *item = FindTopLevelItem(aTopLevel->GetNSAccessible()); - - if (!item) { - MAI_LOG_DEBUG(("MaiAppRoot: new item created\n")); - item = new TopLevelItem(); - NS_ASSERTION(item, "Fail to create TopLevelItem"); - item->ref = 0; - item->maiTopLevel = aTopLevel; - - mTopLevelList = g_list_append(mTopLevelList, item); - AtkObject *atkObject = aTopLevel->GetAtkObject(); - if (atkObject) { - atk_object_set_parent(atkObject, GetAtkObject()); - g_object_ref(atkObject); - } - } - item->ref++; - MAI_LOG_DEBUG(("MaiAppRoot: item ref = %d\n", item->ref)); - - return TRUE; -} - -gboolean -MaiAppRoot::RemoveMaiTopLevel(MaiTopLevel *aTopLevel) -{ - g_return_val_if_fail(aTopLevel != NULL, TRUE); - MAI_LOG_DEBUG(("MaiAppRoot: remove MaiTopLevel = 0x%x", (guint)aTopLevel)); - - TopLevelItem *item = FindTopLevelItem(aTopLevel->GetNSAccessible()); - if (!item) - return FALSE; - item->ref--; - MAI_LOG_DEBUG(("MaiAppRoot: item ref = %d\n", item->ref)); - if (item->ref == 0) { - mTopLevelList = g_list_remove(mTopLevelList, item); - g_object_unref(item->maiTopLevel->GetAtkObject()); - delete item; - MAI_LOG_DEBUG(("MaiAppRoot: Toplevel deleted\n")); + guint uid = aTopLevel->GetNSAccessibleUniqueID(); + g_object_ref(aTopLevel->GetAtkObject()); + if (!LookupTopLevelID(uid)) { + mTopLevelList = g_list_append(mTopLevelList, GINT_TO_POINTER(uid)); + atk_object_set_parent(aTopLevel->GetAtkObject(), GetAtkObject()); } return TRUE; } -MaiTopLevel * -MaiAppRoot::FindMaiTopLevel(MaiTopLevel *aTopLevel) +PRBool +MaiAppRoot::RemoveMaiTopLevelByID(guint aID) { - g_return_val_if_fail(aTopLevel != NULL, FALSE); - return FindMaiTopLevel(aTopLevel->GetNSAccessible()); + if (!LookupTopLevelID(aID)) + return PR_FALSE; + + MaiTopLevel *toplevel = (MaiTopLevel *)MaiHashTable::Lookup(aID); + NS_ASSERTION(toplevel, "Fail to get object from hash table"); + MAI_LOG_DEBUG(("MaiAppRoot: remove MaiTopLevel = 0x%x", (guint)toplevel)); + + if (!toplevel) + return PR_FALSE; + + g_object_unref(toplevel->GetAtkObject()); + return TRUE; } -MaiTopLevel * -MaiAppRoot::FindMaiTopLevel(nsIAccessible *aTopLevel) +PRBool +MaiAppRoot::LookupTopLevelID(guint aID) { - g_return_val_if_fail(aTopLevel != NULL, NULL); - TopLevelItem *item = FindTopLevelItem(aTopLevel); - - if (!item) - return NULL; - - return item->maiTopLevel; -} - -TopLevelItem * -MaiAppRoot::FindTopLevelItem(nsIAccessible *aTopLevel) -{ - g_return_val_if_fail(aTopLevel != NULL, NULL); - - /* use Unique ID of nsIAccessible to judge equal */ if (mTopLevelList) { - GList *tmp_list; - TopLevelItem *item; - - tmp_list = mTopLevelList; - + GList *tmp_list = mTopLevelList; while (tmp_list) { - item = (TopLevelItem*)tmp_list->data; + if (aID == (guint)(tmp_list->data)) + return PR_TRUE; tmp_list = tmp_list->next; - if (item && item->maiTopLevel && - item->maiTopLevel->GetNSAccessibleUniqueID() == - ::GetNSAccessibleUniqueID(aTopLevel)) - return item; } } - return NULL; -} - -MaiCache * -MaiAppRoot::GetCache(void) -{ - // return "NULL" will disable the caching. - return mMaiCache; + return PR_FALSE; } /* virtual functions */ @@ -296,8 +237,12 @@ MaiAppRoot::RefChild(gint aChildIndex) return NULL; } else { - TopLevelItem *item = (TopLevelItem *) - g_list_nth_data(mTopLevelList, aChildIndex); - return item->maiTopLevel; + guint uid = GPOINTER_TO_UINT(g_list_nth_data(mTopLevelList, + aChildIndex)); + MaiTopLevel *maiTopLevel = (MaiTopLevel*)MaiHashTable::Lookup(uid); + NS_ASSERTION(maiTopLevel, "Fail to get object from hash table"); + if (maiTopLevel) + g_object_ref(maiTopLevel->GetAtkObject()); + return maiTopLevel; } } diff --git a/widget/src/gtk2/mai/nsMaiAppRoot.h b/widget/src/gtk2/mai/nsMaiAppRoot.h index 8aed5b22d8b2..562ede4e3512 100644 --- a/widget/src/gtk2/mai/nsMaiAppRoot.h +++ b/widget/src/gtk2/mai/nsMaiAppRoot.h @@ -43,21 +43,10 @@ #define __MAI_APP_ROOT_H__ #include "nsIAccessibleEventReceiver.h" -#include "nsMaiCache.h" #include "nsMaiTopLevel.h" #define MAI_TYPE_APP_ROOT (MAI_TYPE_ATK_OBJECT) -struct TopLevelItem -{ - /* nsIAccessibles for Different toplevel Windows may have same - * Unique ID (why so?), we need to expose only one of them - * "ref" here is used to trace that. - */ - gint ref; - MaiTopLevel *maiTopLevel; -}; - /* MaiAppRoot is the MaiObject class for Mozilla, the whole application. Only * one instance of MaiAppRoot exists for one Mozilla instance. And the one * should be created when Mozilla Startup (with accessibility feature @@ -77,12 +66,9 @@ public: virtual guint GetNSAccessibleUniqueID(); - gboolean AddMaiTopLevel(MaiTopLevel *aToplevel); - gboolean RemoveMaiTopLevel(MaiTopLevel *aToplevel); - MaiTopLevel *FindMaiTopLevel(MaiTopLevel *aToplevel); - MaiTopLevel *FindMaiTopLevel(nsIAccessible *aToplevel); - - MaiCache *GetCache(void); + PRBool AddMaiTopLevel(MaiTopLevel *aToplevel); + PRBool RemoveMaiTopLevelByID(guint aID); + PRBool LookupTopLevelID(guint aID); public: /* virtual functions for MaiObject */ virtual AtkObject *GetAtkObject(void); @@ -96,9 +82,6 @@ public: virtual MaiObject *RefChild(gint aChildIndex); private: GList *mTopLevelList; - TopLevelItem *FindTopLevelItem(nsIAccessible *aAccess); - - MaiCache *mMaiCache; }; #endif /* __MAI_APP_ROOT_H__ */ diff --git a/widget/src/gtk2/mai/nsMaiCache.cpp b/widget/src/gtk2/mai/nsMaiCache.cpp index 065107d96f87..36ef44240033 100644 --- a/widget/src/gtk2/mai/nsMaiCache.cpp +++ b/widget/src/gtk2/mai/nsMaiCache.cpp @@ -45,123 +45,179 @@ MaiCache::MaiCache() { /* cache index always point to the last item */ mCacheIndex = -1; - for (int index = 0; index < MAI_CACHE_SIZE; index++) { - mCache[index].uid = 0; - mCache[index].maiObject = NULL; - } + for (int index = 0; index < MAI_CACHE_SIZE; index++) + mCache[index]= 0; } MaiCache::~MaiCache() { - AtkObject *tmpAtkObj = NULL; + MaiObject *maiObj = NULL; for (int index = 0; index < MAI_CACHE_SIZE; index++) { - if (mCache[index].maiObject && mCache[index].uid != 0) { - tmpAtkObj = mCache[index].maiObject->GetAtkObject(); - MAI_LOG_DEBUG(("Mai Cache: de-caching, maiAtkObj=0x%x, ref=%d\ - maiObj=0x%x, uid=%x\n", (guint)tmpAtkObj, - G_OBJECT(tmpAtkObj)->ref_count, - (guint)mCache[index].maiObject, mCache[index].uid)); - g_object_unref(tmpAtkObj); - mCache[index].uid = 0; - mCache[index].maiObject = NULL; + if ((maiObj = MaiHashTable::Lookup(mCache[index]))) { + MAI_LOG_DEBUG(("Mai Cache: de-caching, uid=0x%x, maiObj=0x%x \n", + mCache[index], maiObj)); + mCache[index] = 0; + g_object_unref(maiObj->GetAtkObject()); } } } -/* more advanced replacing algorithm can be employed for performance - * later in MaiCache::Add - */ -gboolean +PRBool MaiCache::Add(MaiObject *aMaiObj) { - g_return_val_if_fail(aMaiObj != NULL, FALSE); - // different nsIAccessible object can have the same ID, - // but we deem them equal for accessible user. - if (Fetch(aMaiObj)) { - MAI_LOG_DEBUG(("Mai Cache: already in Cache: aMaiObj=0x%x, uid=%x\n", - (guint)aMaiObj, aMaiObj->GetNSAccessibleUniqueID())); - return TRUE; - } + g_return_val_if_fail(aMaiObj != NULL, PR_FALSE); + + guint uid = aMaiObj->GetNSAccessibleUniqueID(); + NS_ASSERTION((uid > 0), "Invalid nsAccessible ID"); + if (uid < 0) + return PR_FALSE; + gint counter = 0; - /* try to find a vacant place */ + /* if it has been in cache */ while (counter < MAI_CACHE_SIZE) { - counter++; + ++counter; mCacheIndex = (++mCacheIndex) % MAI_CACHE_SIZE; - if ((mCache[mCacheIndex].maiObject == NULL) && - (mCache[mCacheIndex].uid == 0)) + if ((mCache[mCacheIndex] == uid)) + return PR_TRUE; + } + + /* try to find a vacant place */ + counter = 0; + while (counter < MAI_CACHE_SIZE) { + ++counter; + mCacheIndex = (++mCacheIndex) % MAI_CACHE_SIZE; + if ((mCache[mCacheIndex] == 0)) break; } - /* if fail to find a vacant place, remove the old */ - AtkObject *tmpAtkObj = NULL; + /* if fail to find a vacant place, remove an old one*/ if (counter >= MAI_CACHE_SIZE) { mCacheIndex = (++mCacheIndex) % MAI_CACHE_SIZE; - tmpAtkObj = mCache[mCacheIndex].maiObject->GetAtkObject(); - MAI_LOG_DEBUG(("Mai Cache: de-caching, maiAtkObj=0x%x, ref=%d \ - maiObj=0x%x, uid=%x\n", (guint)tmpAtkObj, - G_OBJECT(tmpAtkObj)->ref_count, - (guint)mCache[mCacheIndex].maiObject, - (guint)mCache[mCacheIndex].uid)); + MaiObject *tmpMaiObj = MaiHashTable::Lookup(mCache[mCacheIndex]); + NS_ASSERTION(tmpMaiObj, "Fail to lookup from hash table"); + + MAI_LOG_DEBUG(("Mai Cache: de-caching, uid=0x%x, maiObj=0x%x \n", + mCache[mCacheIndex], tmpMaiObj)); MAI_LOG_DEBUG(("Mai Cache: added in %d, replace", mCacheIndex)); - g_object_unref(tmpAtkObj); + g_object_unref(tmpMaiObj->GetAtkObject()); } else MAI_LOG_DEBUG(("Mai Cache: added in %d, vacant", mCacheIndex)); g_object_ref(aMaiObj->GetAtkObject()); - mCache[mCacheIndex].uid = aMaiObj->GetNSAccessibleUniqueID(); - mCache[mCacheIndex].maiObject = aMaiObj; + mCache[mCacheIndex] = uid; MAI_LOG_DEBUG(("Mai Cache: Add in Cache, aMaiObj=0x%x, uid=%x\n", - (guint)aMaiObj, mCache[mCacheIndex].uid)); + (guint)aMaiObj, mCache[mCacheIndex])); - return TRUE; + return PR_TRUE; } -gboolean -MaiCache::Remove(MaiObject *aMaiObj) -{ - g_return_val_if_fail(aMaiObj != NULL, FALSE); - guint uid = aMaiObj->GetNSAccessibleUniqueID(); +/************************************** + nsMaiHashTable +*************************************/ - for (int index = 0; index < MAI_CACHE_SIZE; index++) { - if (mCache[index].uid == uid && mCache[index].maiObject) { - g_object_unref(mCache[index].maiObject->GetAtkObject()); - mCache[index].uid = 0; - mCache[index].maiObject = NULL; - return TRUE; - } +PLHashTable *MaiHashTable::mMaiObjectHashTable = NULL; +PRBool MaiHashTable::mInitialized = PR_FALSE; + +static PLHashNumber IntHashKey(PRInt32 key); + +#ifdef MAI_LOGGING +static PRIntn printHashEntry(PLHashEntry *he, PRIntn index, void *arg); +#endif + +PRBool +MaiHashTable::Init() +{ + if (!mInitialized) { + mMaiObjectHashTable = PL_NewHashTable(0, + (PLHashFunction)IntHashKey, + PL_CompareValues, + PL_CompareValues, + 0, 0); + NS_ASSERTION(mMaiObjectHashTable, "Fail to create Hash Table"); + mInitialized = PR_TRUE; } - return FALSE; + return mInitialized; } -/* the Unique ID of nsIAccessible is the only way to judge if two MaiObject - are equal. So the Fetch(guint uid) is the base for all the other Fetchs -*/ -MaiObject * -MaiCache::Fetch(guint uid) +void +MaiHashTable::Destroy() { - for (int index = 0; index < MAI_CACHE_SIZE; index++) { - if (mCache[index].uid == uid) - return mCache[index].maiObject; + if (mInitialized && mMaiObjectHashTable) { + + mInitialized = PR_FALSE; + +#ifdef MAI_LOGGING + MAI_LOG_DEBUG(("Destroying hash table, but some objs are in it:\n")); + gint count = PL_HashTableEnumerateEntries(mMaiObjectHashTable, + printHashEntry, + (void*)NULL); + MAI_LOG_DEBUG(("Total %d entries still in the hash table\n", count)); +#endif /* #ifdef MAI_LOGGING */ + + PL_HashTableDestroy(mMaiObjectHashTable); + mMaiObjectHashTable = nsnull; } - return NULL; +} + +PRBool +MaiHashTable::Add(MaiObject *aMaiObject) +{ + if (!mInitialized) + return FALSE; + + guint uid = aMaiObject->GetNSAccessibleUniqueID(); + PLHashEntry *newEntry = PL_HashTableAdd(mMaiObjectHashTable, + GINT_TO_POINTER(uid), + GINT_TO_POINTER(aMaiObject)); + MAI_LOG_DEBUG(("--Add in hash table uid=0x%x, obj=0x%x\n", + uid, (guint)aMaiObject)); + return newEntry ? PR_TRUE : PR_FALSE; +} + +PRBool +MaiHashTable::Remove(MaiObject *aMaiObject) +{ + if (!mInitialized) + return FALSE; + + guint uid = aMaiObject->GetNSAccessibleUniqueID(); + MAI_LOG_DEBUG(("--Remove in hash table uid=0x%x, obj=0x%x\n", + uid, (guint)aMaiObject)); + return PL_HashTableRemove(mMaiObjectHashTable, GINT_TO_POINTER(uid)); } MaiObject * -MaiCache::Fetch(MaiObject *aMaiObj) +MaiHashTable::Lookup(guint uid) { - return Fetch(aMaiObj->GetNSAccessibleUniqueID()); + if (!mInitialized) + return FALSE; + + return NS_REINTERPRET_CAST(MaiObject*, + PL_HashTableLookup(mMaiObjectHashTable, + GINT_TO_POINTER(uid))); } MaiObject * -MaiCache::Fetch(nsIAccessible *aAccess) +MaiHashTable::Lookup(nsIAccessible *aAcc) { - return Fetch(GetNSAccessibleUniqueID(aAccess)); + return Lookup(::GetNSAccessibleUniqueID(aAcc)); } -MaiObject * -MaiCache::Fetch(AtkObject *aAtkObj) +PLHashNumber +IntHashKey(PRInt32 key) { - MAI_CHECK_ATK_OBJECT_RETURN_VAL_IF_FAIL(aAtkObj, NULL); - return Fetch(MAI_ATK_OBJECT(aAtkObj)->maiObject); + return PLHashNumber(key); } + +#ifdef MAI_LOGGING +PRIntn +printHashEntry(PLHashEntry *he, PRIntn index, void *arg) +{ + if (he) { + MAI_LOG_DEBUG((" Entry: uid=0x%x, maiObj=0x%x\n", + (guint)he->key, (guint)he->value)); + } + return HT_ENUMERATE_NEXT; +} +#endif /* #ifdef MAI_LOGGING */ diff --git a/widget/src/gtk2/mai/nsMaiCache.h b/widget/src/gtk2/mai/nsMaiCache.h index 68aa908655ce..6d5e5eb9b221 100644 --- a/widget/src/gtk2/mai/nsMaiCache.h +++ b/widget/src/gtk2/mai/nsMaiCache.h @@ -42,13 +42,21 @@ #ifndef __MAI_CACHE_H__ #define __MAI_CACHE_H__ +#include "plhash.h" #include "nsMaiObject.h" -struct MaiCacheItem -{ - guint uid; - MaiObject *maiObject; -}; +//////////////////////////////////////////////////////////////// +// Class MaiCache +// ---------------------- +// +// MaiCache keeps some maiObjects in memory for a longer time +// when they are going to be released in the normal case (no cache) +// For this aim, MaiCache increases the maiobject refcount by one, +// thus the maiobject will reside in memory at least when MaiCache +// releases it. +// The cached maiobjects are not needed to be saved in cache, they are +// in hash table. MaiCache only saves the IDs of cached objects. +////////////////////////////////////////////////////////////////// class MaiCache { @@ -56,17 +64,29 @@ public: MaiCache(); ~MaiCache(); - gboolean Add(MaiObject *aMaiObj); - gboolean Remove(MaiObject *aMaiObj); - MaiObject *Fetch(guint uid); - MaiObject *Fetch(MaiObject *aMaiObj); - MaiObject *Fetch(nsIAccessible *aAccess); - MaiObject *Fetch(AtkObject *aAtkObj); - + PRBool Add(MaiObject *aMaiObj); private: enum { MAI_CACHE_SIZE = 10 }; - MaiCacheItem mCache [MAI_CACHE_SIZE]; + guint mCache[MAI_CACHE_SIZE]; gint mCacheIndex; }; +class MaiHashTable +{ +public: + MaiHashTable() {} + ~MaiHashTable() {} +public: + static PRBool Init(void); + static void Destroy(void); + + static PRBool Add(MaiObject *); + static PRBool Remove(MaiObject *); + static MaiObject *Lookup(guint uid); + static MaiObject *Lookup(nsIAccessible *aAcc); +private: + static PLHashTable *mMaiObjectHashTable; + static PRBool mInitialized; +}; + #endif /* __MAI_CACHE_H__ */ diff --git a/widget/src/gtk2/mai/nsMaiHyperlink.cpp b/widget/src/gtk2/mai/nsMaiHyperlink.cpp index 313c84cf247a..0c3b2429e679 100644 --- a/widget/src/gtk2/mai/nsMaiHyperlink.cpp +++ b/widget/src/gtk2/mai/nsMaiHyperlink.cpp @@ -156,8 +156,7 @@ MaiHyperlink::GetObject(gint aLinkIndex) if (NS_FAILED(rv) || !accObj) return NULL; - /* ??? when the new one get freed? */ - MaiWidget *maiObj = new MaiWidget(accObj); + MaiWidget *maiObj = MaiWidget::CreateAndCache(accObj); return maiObj; } diff --git a/widget/src/gtk2/mai/nsMaiInterfaceTable.cpp b/widget/src/gtk2/mai/nsMaiInterfaceTable.cpp index 4d50bfb602de..cfa41fd22b4c 100644 --- a/widget/src/gtk2/mai/nsMaiInterfaceTable.cpp +++ b/widget/src/gtk2/mai/nsMaiInterfaceTable.cpp @@ -344,7 +344,7 @@ MaiInterfaceTable::GetSummary() gint MaiInterfaceTable::GetSelectedColumns(gint **aSelected) { - MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, NULL); + MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, 0); PRUint32 size = 0; PRInt32 *columns = NULL; @@ -358,7 +358,7 @@ MaiInterfaceTable::GetSelectedColumns(gint **aSelected) NS_ASSERTION(atkColumns, "Fail to get memory for columns"); //copy - for (int index = 0; index < size; ++index) + for (PRUint32 index = 0; index < size; ++index) atkColumns[index] = NS_STATIC_CAST(gint, columns[index]); nsMemory::Free(columns); @@ -369,7 +369,7 @@ MaiInterfaceTable::GetSelectedColumns(gint **aSelected) gint MaiInterfaceTable::GetSelectedRows(gint **aSelected) { - MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, NULL); + MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, 0); PRUint32 size = 0; PRInt32 *rows = NULL; @@ -383,7 +383,7 @@ MaiInterfaceTable::GetSelectedRows(gint **aSelected) NS_ASSERTION(atkRows, "Fail to get memory for rows"); //copy - for (int index = 0; index < size; ++index) + for (PRUint32 index = 0; index < size; ++index) atkRows[index] = NS_STATIC_CAST(gint, rows[index]); nsMemory::Free(rows); diff --git a/widget/src/gtk2/mai/nsMaiObject.cpp b/widget/src/gtk2/mai/nsMaiObject.cpp index 72dc74fd5479..bea8107552ab 100644 --- a/widget/src/gtk2/mai/nsMaiObject.cpp +++ b/widget/src/gtk2/mai/nsMaiObject.cpp @@ -40,6 +40,8 @@ * ***** END LICENSE BLOCK ***** */ #include "nsMaiObject.h" +#include "nsMaiUtil.h" +#include "nsMaiCache.h" #include "nsIAccessibleEventListener.h" #include "nsString.h" @@ -139,6 +141,7 @@ MaiObject::MaiObject(nsIAccessible *aAcc) #endif MAI_LOG_DEBUG(("====MaiObject creating this=0x%x,total =%d= created\n", (unsigned int)this, num_created_mai_object)); + } MaiObject::~MaiObject() @@ -323,6 +326,9 @@ finalizeCB(GObject *aObj) MaiObject *maiObject = MAI_ATK_OBJECT(aObj)->maiObject; MAI_LOG_DEBUG(("====release MaiAtkObject=0x%x, MaiObject=0x%x\n", (guint)aObj, (guint)maiObject)); + + MaiHashTable::Remove(maiObject); + maiObject->Finalize(); // never call MaiObject later @@ -385,14 +391,7 @@ refChildCB(AtkObject *aObj, gint aChildIndex) if (!childObject) return NULL; - AtkObject *childAtkObj = childObject->GetAtkObject(); - if (childAtkObj) { - g_object_ref(childAtkObj); - if (!childAtkObj->accessible_parent) - //this will addref parent - atk_object_set_parent(childAtkObj, aObj); - } - return childAtkObj; + return childObject->GetAtkObject(); } gint diff --git a/widget/src/gtk2/mai/nsMaiTopLevel.cpp b/widget/src/gtk2/mai/nsMaiTopLevel.cpp index 1799b7d8ea3c..e17ac28fb3c8 100644 --- a/widget/src/gtk2/mai/nsMaiTopLevel.cpp +++ b/widget/src/gtk2/mai/nsMaiTopLevel.cpp @@ -88,40 +88,83 @@ MaiTopLevel::~MaiTopLevel() receiver->RemoveAccessibleEventListener(); } +////////////////////////////////////////////////////////////////////// +// See the comments in +// MaiWidget::Create(nsIAccessible *aAcc); +///////////////////////////////////////////////////////////////////// +MaiTopLevel * +MaiTopLevel::Create(nsIAccessible *aAcc) +{ + if (!aAcc) + return NULL; + + MaiTopLevel *maiTopLevel = NS_REINTERPRET_CAST(MaiTopLevel *, + MaiHashTable::Lookup(aAcc)); + if (!maiTopLevel) { + maiTopLevel = new MaiTopLevel(aAcc); + NS_ASSERTION(maiTopLevel, "Fail to create Object\n"); + NS_IF_ADDREF(maiTopLevel); + MaiHashTable::Add(maiTopLevel); + } + else { + g_object_ref(maiTopLevel->GetAtkObject()); + } + return maiTopLevel; +} + +////////////////////////////////////////////////////////////////////// +// See the comments in +// MaiWidget::CreateAndCache(nsIAccessible *aAcc); +///////////////////////////////////////////////////////////////////// +MaiTopLevel * +MaiTopLevel::CreateAndCache(nsIAccessible *aAcc) +{ + if (!aAcc) + return NULL; + + MaiCache *maiCache = mai_get_cache(); + if (!maiCache) + return NULL; + MaiTopLevel *retWidget = MaiTopLevel::Create(aAcc); + maiCache->Add(retWidget); + + return retWidget; +} + NS_IMETHODIMP MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, AccessibleEventData * aEventData) { - MaiWidget *pMaiObject; + nsresult rv = NS_ERROR_FAILURE; + MaiWidget *pMaiObject = NULL; AtkTableChange * pAtkTableChange; MAI_LOG_DEBUG(("\n\nReceived event: aEvent=%u, obj=0x%x, data=0x%x \n", aEvent, aAccessible, aEventData)); - if (mAccessible == aAccessible) - pMaiObject = this; - else - pMaiObject = CreateMaiWidgetFor(aAccessible); + pMaiObject = CreateMaiWidgetFor(aAccessible); if (!pMaiObject) { MAI_LOG_DEBUG(("\n\nFail to Create MaiObject for obj=0x%x\n", aAccessible)); - return NS_ERROR_FAILURE; + return NS_ERROR_OUT_OF_MEMORY; } + MaiObject *oldMaiObj = NULL, *newMaiObj = NULL; switch (aEvent) { case nsIAccessibleEventListener::EVENT_FOCUS: MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n")); atk_focus_tracker_notify(ATK_OBJECT(pMaiObject->GetAtkObject())); + rv = NS_OK; break; - + case nsIAccessibleEventListener::EVENT_STATE_CHANGE: AtkStateChange *pAtkStateChange; AtkStateType atkState; MAI_LOG_DEBUG(("\n\nReceived: EVENT_STATE_CHANGE\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; pAtkStateChange = NS_REINTERPRET_CAST(AtkStateChange *, aEventData); @@ -138,6 +181,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, atk_object_notify_state_change(ATK_OBJECT(pMaiObject->GetAtkObject()), atkState, pAtkStateChange->enable); + rv = NS_OK; break; /* @@ -150,37 +194,42 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_PROPERTY_CHANGE\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; pAtkPropChange = NS_REINTERPRET_CAST(AtkPropertyChange *, aEventData); values.property_name = pAtkPropertyNameArray[pAtkPropChange->type]; MAI_LOG_DEBUG(("\n\nthe type of EVENT_ATK_PROPERTY_CHANGE: %d\n\n", pAtkPropChange->type)); + switch (pAtkPropChange->type) { case PROP_TABLE_CAPTION: case PROP_TABLE_SUMMARY: - MaiObject *aOldMaiObj, *aNewMaiObj; if (pAtkPropChange->oldvalue) - aOldMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST - (nsIAccessible *, - pAtkPropChange->oldvalue)); + oldMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST + (nsIAccessible *, + pAtkPropChange->oldvalue)); if (pAtkPropChange->newvalue) - aNewMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST - (nsIAccessible *, - pAtkPropChange->newvalue)); + newMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST + (nsIAccessible *, + pAtkPropChange->newvalue)); - if (!aOldMaiObj || !aNewMaiObj ) - return NS_ERROR_FAILURE; + if (oldMaiObj && newMaiObj) { + g_value_init(&values.old_value, G_TYPE_POINTER); + g_value_set_pointer(&values.old_value, + ATK_OBJECT(oldMaiObj->GetAtkObject())); + g_value_init(&values.new_value, G_TYPE_POINTER); + g_value_set_pointer(&values.new_value, + ATK_OBJECT(newMaiObj->GetAtkObject())); + rv = NS_OK; + } + if (oldMaiObj) + g_object_unref(oldMaiObj->GetAtkObject()); + if (newMaiObj) + g_object_unref(newMaiObj->GetAtkObject()); - g_value_init(&values.old_value, G_TYPE_POINTER); - g_value_set_pointer(&values.old_value, - ATK_OBJECT(aOldMaiObj->GetAtkObject())); - g_value_init(&values.new_value, G_TYPE_POINTER); - g_value_set_pointer(&values.new_value, - ATK_OBJECT(aNewMaiObj->GetAtkObject())); break; case PROP_TABLE_COLUMN_DESCRIPTION: @@ -191,6 +240,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, g_value_set_int(&values.new_value, *NS_REINTERPRET_CAST(gint *, pAtkPropChange->newvalue)); + rv = NS_OK; break; //Perhaps need more cases in the future @@ -199,12 +249,13 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, g_value_set_pointer (&values.old_value, pAtkPropChange->oldvalue); g_value_init (&values.new_value, G_TYPE_POINTER); g_value_set_pointer (&values.new_value, pAtkPropChange->newvalue); + rv = NS_OK; } - - g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), - g_strconcat("property_change::", - values.property_name), - &values, NULL); + if (NS_SUCCEEDED(rv)) + g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), + g_strconcat("property_change::", + values.property_name), + &values, NULL); break; @@ -212,6 +263,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_SELECTION_CHANGE\n")); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "selection_changed"); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TEXT_CHANGE: @@ -219,7 +271,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_CHANGE\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; pAtkTextChange = NS_REINTERPRET_CAST(AtkTextChange *, aEventData); g_signal_emit_by_name (ATK_OBJECT(pMaiObject->GetAtkObject()), @@ -227,36 +279,40 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, "text_changed::insert":"text_changed::delete", pAtkTextChange->start, pAtkTextChange->length); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TEXT_SELECTION_CHANGE: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_SELECTION_CHANGE\n")); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "text_selection_changed"); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TEXT_CARET_MOVE: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_CARET_MOVE\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; MAI_LOG_DEBUG(("\n\nCaret postion: %d", *(gint *)aEventData )); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "text_caret_moved", // Curent caret position *(gint *)aEventData); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TABLE_MODEL_CHANGE: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_MODEL_CHANGE\n")); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "model_changed"); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_INSERT: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_INSERT\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); @@ -266,12 +322,13 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, pAtkTableChange->index, // The number of the inserted pAtkTableChange->count); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_DELETE: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_DELETE\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); @@ -281,18 +338,20 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, pAtkTableChange->index, // The number of the deleted pAtkTableChange->count); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_REORDER: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_REORDER\n")); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "row_reordered"); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_INSERT: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_INSERT\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); @@ -302,12 +361,13 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, pAtkTableChange->index, // The number of the inserted pAtkTableChange->count); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_DELETE: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_DELETE\n")); if (!aEventData) - return NS_ERROR_FAILURE; + break; pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); @@ -317,18 +377,21 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, pAtkTableChange->index, // The number of the deleted pAtkTableChange->count); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_REORDER: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_REORDER\n")); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "column_reordered"); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_ATK_VISIBLE_DATA_CHANGE: MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_VISIBLE_DATA_CHANGE\n")); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "visible_data_changed"); + rv = NS_OK; break; // Is a superclass of ATK event children_changed @@ -352,6 +415,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, pAtkChildrenChange->index, ATK_OBJECT(childMaiObject->GetAtkObject()), NULL); + g_object_unref(childMaiObject->GetAtkObject()); } else { g_signal_emit_by_name (ATK_OBJECT(pMaiObject->GetAtkObject()), @@ -359,6 +423,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, -1, NULL, NULL); } + rv = NS_OK; break; /* @@ -372,12 +437,14 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, atk_focus_tracker_notify(ATK_OBJECT(pMaiObject->GetAtkObject())); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "selection_changed"); + rv = NS_OK; break; case nsIAccessibleEventListener::EVENT_MENUEND: MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUEND\n")); g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), "selection_changed"); + rv = NS_OK; break; default: @@ -386,7 +453,9 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, break; } - return NS_OK; + if (pMaiObject) + g_object_unref(pMaiObject->GetAtkObject()); + return rv; } /****************************************************************** @@ -400,41 +469,6 @@ MaiTopLevel::CreateMaiWidgetFor(nsIAccessible *aAccessible) return MaiWidget::CreateAndCache(aAccessible); } -/*static*/ -////////////////////////////////////////////////////////////////////// -// See the comments in -// MaiWidget::CreateAndCache(nsIAccessible *aAcc); -///////////////////////////////////////////////////////////////////// -MaiTopLevel * -MaiTopLevel::CreateAndCache(nsIAccessible *aAcc) -{ - if (!aAcc) - return NULL; - - MaiCache *maiCache = mai_get_cache(); - if (!maiCache) - return NULL; - - MaiTopLevel *retWidget = - NS_STATIC_CAST(MaiTopLevel*, maiCache->Fetch(aAcc)); - //there is a maiWidget in cache for the nsIAccessible already. - if (retWidget) { - MAI_LOG_DEBUG(("MaiTopLevel::CreateAndCache, already added\n")); - return retWidget; - } - - //create one, and cache it. - retWidget = new MaiTopLevel(aAcc); - NS_ASSERTION(retWidget, "Fail to create mai object"); - MAI_LOG_DEBUG(("MaiTopLevel::CreateAndCache, new one created\n")); - - maiCache->Add(retWidget); - //cache should have add ref, release ours - g_object_unref(retWidget->GetAtkObject()); - - return retWidget; -} - /* static */ AtkStateType MaiTopLevel::TranslateAState(PRUint32 aAccState) diff --git a/widget/src/gtk2/mai/nsMaiTopLevel.h b/widget/src/gtk2/mai/nsMaiTopLevel.h index 4287acf4c30b..37969d88ea88 100644 --- a/widget/src/gtk2/mai/nsMaiTopLevel.h +++ b/widget/src/gtk2/mai/nsMaiTopLevel.h @@ -56,6 +56,7 @@ class MaiTopLevel: public MaiWidget, public nsIAccessibleEventListener public: MaiTopLevel(nsIAccessible *aAcc); virtual ~MaiTopLevel(); + static MaiTopLevel * Create(nsIAccessible *aAcc); NS_DECL_ISUPPORTS // nsIAccessibleEventListener diff --git a/widget/src/gtk2/mai/nsMaiUtil.cpp b/widget/src/gtk2/mai/nsMaiUtil.cpp index 40e0f10f515f..1f454dd667f6 100644 --- a/widget/src/gtk2/mai/nsMaiUtil.cpp +++ b/widget/src/gtk2/mai/nsMaiUtil.cpp @@ -42,12 +42,17 @@ #include #include "nsMaiUtil.h" +#include "nsMaiCache.h" #include "nsMaiAppRoot.h" static gboolean mai_shutdown(void); static void mai_delete_root(void); static MaiAppRoot *mai_create_root(void); +MaiCache *mai_create_cache(void); +MaiCache *mai_get_cache(void); +void mai_delete_cache(void); + static void mai_util_class_init(MaiUtilClass *klass); /* atkutil.h */ @@ -305,6 +310,9 @@ mai_init(MaiHook **aMaiHook) /* Initialize the MAI Utility class */ g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL)); + MaiHashTable::Init(); + mai_create_cache(); + return TRUE; } @@ -323,6 +331,9 @@ mai_shutdown(void) sMaiHook.RemoveTopLevelAccessible = NULL; mai_delete_root(); + mai_delete_cache(); + MaiHashTable::Destroy(); + return TRUE; } @@ -338,6 +349,7 @@ mai_create_root(void) } if (!sRootAccessible) { sRootAccessible = new MaiAppRoot(); + MaiHashTable::Add(sRootAccessible); NS_ASSERTION(sRootAccessible, "Fail to create MaiAppRoot"); /* initialize the MAI hook @@ -363,23 +375,41 @@ void mai_delete_root(void) { if (sRootAccessible) { - delete sRootAccessible; + g_object_unref(sRootAccessible->GetAtkObject()); sRootAccessible = NULL; } } /* return the reference of MaiCache. */ +static MaiCache *sMaiCache = NULL; + MaiCache * -mai_get_cache(void) +mai_create_cache(void) { if (!mai_initialized) { return NULL; } - MaiAppRoot *root = mai_get_root(); - if (root) - return root->GetCache(); - return NULL; + if (!sMaiCache) { + sMaiCache = new MaiCache(); + NS_ASSERTION(sMaiCache, "Fail to create MaiCache"); + } + return sMaiCache; +} + +MaiCache * +mai_get_cache(void) +{ + return sMaiCache; +} + +void +mai_delete_cache(void) +{ + if (sMaiCache) { + delete sMaiCache; + sMaiCache = NULL; + } } gboolean @@ -387,35 +417,16 @@ mai_add_toplevel_accessible(nsIAccessible *toplevel) { g_return_val_if_fail(toplevel != NULL, TRUE); -#if 1 MaiAppRoot *root; root = mai_get_root(); if (!root) return FALSE; - MaiTopLevel *mai_top_level = new MaiTopLevel(toplevel); + + MaiTopLevel *mai_top_level = MaiTopLevel::Create(toplevel); g_return_val_if_fail(mai_top_level != NULL, PR_FALSE); gboolean res = root->AddMaiTopLevel(mai_top_level); - - /* root will add ref for itself use */ g_object_unref(mai_top_level->GetAtkObject()); return res; -#endif - -#if 0 - MaiAppRoot *root; - root = mai_get_root(); - if (!root) - return FALSE; - - MaiTopLevel *mai_top_level = - NS_STATIC_CAST(MaiTopLevel*, MaiTopLevel::CreateAndCache(toplevel)); - - g_return_val_if_fail(mai_top_level != NULL, PR_FALSE); - gboolean res = root->AddMaiTopLevel(mai_top_level); - - return res; -#endif - } gboolean @@ -426,8 +437,9 @@ mai_remove_toplevel_accessible(nsIAccessible *toplevel) MaiAppRoot *root; root = mai_get_root(); if (root) { - MaiTopLevel *mai_top_level = root->FindMaiTopLevel(toplevel); - return root->RemoveMaiTopLevel(mai_top_level); + guint uid = ::GetNSAccessibleUniqueID(toplevel); + gboolean res = root->RemoveMaiTopLevelByID(uid); + return res; } else return FALSE; diff --git a/widget/src/gtk2/mai/nsMaiUtil.h b/widget/src/gtk2/mai/nsMaiUtil.h index 1f911abee9e2..11d2f2b2614b 100644 --- a/widget/src/gtk2/mai/nsMaiUtil.h +++ b/widget/src/gtk2/mai/nsMaiUtil.h @@ -77,7 +77,7 @@ struct _MaiUtilClass }; #define MAI_VERSION "0.0.6" -#define MAI_NAME "MAI-Mozilla Atk Interface" +#define MAI_NAME "mozilla" MaiAppRoot *mai_get_root(void); MaiCache *mai_get_cache(void); diff --git a/widget/src/gtk2/mai/nsMaiWidget.cpp b/widget/src/gtk2/mai/nsMaiWidget.cpp index f0c7a785c1a3..d0c245a7f3e5 100644 --- a/widget/src/gtk2/mai/nsMaiWidget.cpp +++ b/widget/src/gtk2/mai/nsMaiWidget.cpp @@ -60,6 +60,7 @@ #include "nsMaiInterfaceValue.h" #include "nsMaiUtil.h" +#include "nsMaiCache.h" G_BEGIN_DECLS @@ -120,6 +121,69 @@ MaiWidget::~MaiWidget() g_hash_table_destroy(mChildren); } +/////////////////////////////////////////////////////////////////////// +// MaiWidget * +// MaiWidget::Create(nsIAccessible *aAcc) +//------------------------------------------------------------------- +// +// This method return a maiWidget for |aAcc|. If There is a maiWidget whose +// ID is same with |aAcc|, the old one is returned and |aAcc| is discarded. +// Otherwise, a new MaiWidget is created and returned, which will ADDREF +// |aAcc|. In both cases, the atkObject for the maiWidget returned has been +// addrefed. That is to say, a the refcount of the gobject is one for a new +// created maiWidget, or increased by one for a already existing maiWidget. +// The caller is REQUIRED to release the refcount. +// +// **Note** +// Any active mai object is saved in the MaiHashTable, until it is deleted. +// An Mai Object can only be deleted when its atk object refcount reachs +// zero. + +MaiWidget * +MaiWidget::Create(nsIAccessible *aAcc) +{ + if (!aAcc) + return NULL; + + MaiWidget *maiWidget = NS_REINTERPRET_CAST(MaiWidget *, + MaiHashTable::Lookup(aAcc)); + if (!maiWidget) { + //atkObject born with refcount=1, no need to addref it. + maiWidget = new MaiWidget(aAcc); + NS_ASSERTION(maiWidget, "Fail to create Object\n"); + MaiHashTable::Add(maiWidget); + } + else { + MAI_LOG_DEBUG(("find maiWidget=0x%x in hash table for uid=0x%x\n", + (guint)maiWidget, ::GetNSAccessibleUniqueID(aAcc))); + g_object_ref(maiWidget->GetAtkObject()); + } + return maiWidget; +} + +/*static*/ +////////////////////////////////////////////////////////////////////// +// MaiWidget * +// MaiWidget::CreateAndCache(nsIAccessible *aAcc); +// +// this function will call MaiWidget::Create, and cache the result. +//////////////////////////////////////////////////////////////////////// +MaiWidget * +MaiWidget::CreateAndCache(nsIAccessible *aAcc) +{ + if (!aAcc) + return NULL; + + MaiCache *maiCache = mai_get_cache(); + if (!maiCache) + return NULL; + + //create one, and cache it. + MaiWidget *retWidget = MaiWidget::Create(aAcc); + maiCache->Add(retWidget); + return retWidget; +} + #ifdef MAI_LOGGING void MaiWidget::DumpMaiObjectInfo(gint aDepth) @@ -167,61 +231,12 @@ MaiWidget::GetMaiInterface(MaiInterfaceType aIfaceType) return mMaiInterface[aIfaceType]; } -/*static*/ -////////////////////////////////////////////////////////////////////// -// MaiWidget * -// MaiWidget::CreateAndCache(nsIAccessible *aAcc); -// -// A helper to create a new MaiWidget and cache it. -//------------------------------------------------------------------- -// This Method gets a cached MaiWidget for the nsIAccessible, create one -// if needed and cache it. Only when create a new MaiWidget, |aAcc| will -// be addrefed. -// -// **Note** -// The returned cached MaiWidget object is NOT guaranteed to be there when -// you fetch it next time. Accordingly, DO NOT keep the returned pointer -// and use it later. Typically, you pass the result of this method to a -// callback. -// If it is really needed to keep the result for later use, please use -// g_object_ref(maiWidget->GetAtkObject()); -// to ensure the |maiWidget| pointer is still valid, even when the MaiWidget -// is removed from the cache. And when you do not need it, you have to use: -// g_object_unref(maiWidget->GetAtkObject()); -// to release your reference. -//////////////////////////////////////////////////////////////////////// -MaiWidget * -MaiWidget::CreateAndCache(nsIAccessible *aAcc) -{ - if (!aAcc) - return NULL; - - MaiCache *maiCache = mai_get_cache(); - if (!maiCache) - return NULL; - - MaiWidget *retWidget = NS_STATIC_CAST(MaiWidget*, maiCache->Fetch(aAcc)); - //there is a maiWidget in cache for the nsIAccessible already. - if (retWidget) - return retWidget; - - //create one, and cache it. - retWidget = new MaiWidget(aAcc); - NS_ASSERTION(retWidget, "Fail to create mai object"); - - maiCache->Add(retWidget); - //cache should have add ref, release ours - g_object_unref(retWidget->GetAtkObject()); - - return retWidget; -} - void MaiWidget::ChildrenChange(AtkChildrenChange *event) { MaiWidget *maiChild; if (event && event->child && - (maiChild = CreateAndCache(event->child))) { + (maiChild = Create(event->child))) { //update the specified child, but now use the easiest way. g_hash_table_destroy(mChildren); mChildren = g_hash_table_new(g_direct_hash, NULL); @@ -407,7 +422,7 @@ MaiWidget::GetParent(void) return NULL; /* create a maiWidget for parent */ - return CreateAndCache(accParent); + return Create(accParent); } gint @@ -430,16 +445,19 @@ MaiWidget::RefChild(gint aChildIndex) MaiObject *maiChild = NULL; guint uid; - // look in cache first - MaiCache *maiCache = mai_get_cache(); - if (maiCache) { - uid = GetChildUniqueID(aChildIndex); - if (uid > 0 && (maiChild = maiCache->Fetch(uid))) { - MAI_LOG_DEBUG(("got child 0x%x from cache\n", (guint)maiChild)); - return maiChild; - } + + // look in hashtable first + uid = GetChildUniqueID(aChildIndex); + if (uid > 0 && (maiChild = MaiHashTable::Lookup(uid))) { + MAI_LOG_DEBUG(("got child 0x%x from hash table\n", (guint)maiChild)); + g_object_ref(maiChild->GetAtkObject()); + + //this will addref parent + atk_object_set_parent(maiChild->GetAtkObject(), GetAtkObject()); + return maiChild; } - // :( not cached yet, get and cache it is possible + + // :( not in child list or hash table yet // nsIAccessible child index starts with 1 gint accChildIndex = 1; nsCOMPtr accChild = NULL; @@ -459,16 +477,12 @@ MaiWidget::RefChild(gint aChildIndex) // user, since they point to the same dom node. // So, maybe the it has been cached. uid = ::GetNSAccessibleUniqueID(accChild); - g_return_val_if_fail(uid != 0, NULL); - if (maiCache) - maiChild = maiCache->Fetch(uid); - - // not cached, create one - if (!maiChild) { - maiChild = CreateAndCache(accChild); - } // update children uid list SetChildUniqueID(aChildIndex, uid); + maiChild = Create(accChild); + + //this will addref parent + atk_object_set_parent(maiChild->GetAtkObject(), GetAtkObject()); return maiChild; } @@ -552,7 +566,7 @@ MaiWidget::SetChildUniqueID(gint aChildIndex, guint aChildUid) void classInitCB(AtkObjectClass *aClass) { - GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); + // GObjectClass *gobject_class = G_OBJECT_CLASS(aClass); parent_class = g_type_class_peek_parent(aClass); diff --git a/widget/src/gtk2/mai/nsMaiWidget.h b/widget/src/gtk2/mai/nsMaiWidget.h index 781e8e8c2ebf..109d9aff9ba9 100644 --- a/widget/src/gtk2/mai/nsMaiWidget.h +++ b/widget/src/gtk2/mai/nsMaiWidget.h @@ -85,6 +85,8 @@ class MaiWidget: public MaiObject public: MaiWidget(nsIAccessible *aAcc); virtual ~MaiWidget(); + static MaiWidget *Create(nsIAccessible *aAcc); + #ifdef MAI_LOGGING virtual void DumpMaiObjectInfo(int aDepth); #endif