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
This commit is contained in:
bolian.yin%sun.com 2002-10-24 03:06:04 +00:00
Родитель 75d069ac37
Коммит 6f7d1e2855
13 изменённых файлов: 453 добавлений и 388 удалений

Просмотреть файл

@ -41,15 +41,13 @@
#include "nsIAccessible.h" #include "nsIAccessible.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsMaiCache.h"
#include "nsMaiAppRoot.h" #include "nsMaiAppRoot.h"
MaiAppRoot::MaiAppRoot() MaiAppRoot::MaiAppRoot()
{ {
/* for mai root, mAccessible is always NULL */ /* for mai root, mAccessible is always NULL */
mTopLevelList = NULL; mTopLevelList = NULL;
mMaiCache = new MaiCache();
NS_ASSERTION(mMaiCache, "Fail to create MaiCache");
} }
MaiAppRoot::~MaiAppRoot() MaiAppRoot::~MaiAppRoot()
@ -59,23 +57,23 @@ MaiAppRoot::~MaiAppRoot()
if (mTopLevelList) { if (mTopLevelList) {
GList *tmp_list1, *tmp_list2; GList *tmp_list1, *tmp_list2;
MaiTopLevel *maiTopLevel; MaiTopLevel *maiTopLevel;
guint uid;
tmp_list1 = tmp_list2 = mTopLevelList; tmp_list1 = tmp_list2 = mTopLevelList;
mTopLevelList = NULL; mTopLevelList = NULL;
#ifdef MAI_LOGGING
while (tmp_list1) { 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; tmp_list1 = tmp_list1->next;
g_object_unref(maiTopLevel->GetAtkObject());
} }
g_list_free(tmp_list2); #endif /* #ifdef MAI_LOGGING */
mTopLevelList = NULL;
}
if (mMaiCache) { g_list_free(tmp_list2);
delete mMaiCache;
mMaiCache = NULL;
} }
} }
@ -116,107 +114,50 @@ MaiAppRoot::GetNSAccessibleUniqueID()
return 1; return 1;
} }
gboolean PRBool
MaiAppRoot::AddMaiTopLevel(MaiTopLevel *aTopLevel) MaiAppRoot::AddMaiTopLevel(MaiTopLevel *aTopLevel)
{ {
g_return_val_if_fail(aTopLevel != NULL, FALSE); g_return_val_if_fail(aTopLevel != NULL, FALSE);
MAI_LOG_DEBUG(("MaiAppRoot: add MaiTopLevel = 0x%x", (guint)aTopLevel)); MAI_LOG_DEBUG(("MaiAppRoot: add MaiTopLevel = 0x%x", (guint)aTopLevel));
/* if the nsIAccessible with the same UniqueID is already added, guint uid = aTopLevel->GetNSAccessibleUniqueID();
* we only increase the count of this item in the list. g_object_ref(aTopLevel->GetAtkObject());
* They are same. if (!LookupTopLevelID(uid)) {
*/ mTopLevelList = g_list_append(mTopLevelList, GINT_TO_POINTER(uid));
atk_object_set_parent(aTopLevel->GetAtkObject(), GetAtkObject());
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"));
} }
return TRUE; return TRUE;
} }
MaiTopLevel * PRBool
MaiAppRoot::FindMaiTopLevel(MaiTopLevel *aTopLevel) MaiAppRoot::RemoveMaiTopLevelByID(guint aID)
{ {
g_return_val_if_fail(aTopLevel != NULL, FALSE); if (!LookupTopLevelID(aID))
return FindMaiTopLevel(aTopLevel->GetNSAccessible()); 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 * PRBool
MaiAppRoot::FindMaiTopLevel(nsIAccessible *aTopLevel) 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) { if (mTopLevelList) {
GList *tmp_list; GList *tmp_list = mTopLevelList;
TopLevelItem *item;
tmp_list = mTopLevelList;
while (tmp_list) { while (tmp_list) {
item = (TopLevelItem*)tmp_list->data; if (aID == (guint)(tmp_list->data))
return PR_TRUE;
tmp_list = tmp_list->next; tmp_list = tmp_list->next;
if (item && item->maiTopLevel &&
item->maiTopLevel->GetNSAccessibleUniqueID() ==
::GetNSAccessibleUniqueID(aTopLevel))
return item;
} }
} }
return NULL; return PR_FALSE;
}
MaiCache *
MaiAppRoot::GetCache(void)
{
// return "NULL" will disable the caching.
return mMaiCache;
} }
/* virtual functions */ /* virtual functions */
@ -296,8 +237,12 @@ MaiAppRoot::RefChild(gint aChildIndex)
return NULL; return NULL;
} }
else { else {
TopLevelItem *item = (TopLevelItem *) guint uid = GPOINTER_TO_UINT(g_list_nth_data(mTopLevelList,
g_list_nth_data(mTopLevelList, aChildIndex); aChildIndex));
return item->maiTopLevel; 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;
} }
} }

Просмотреть файл

@ -43,21 +43,10 @@
#define __MAI_APP_ROOT_H__ #define __MAI_APP_ROOT_H__
#include "nsIAccessibleEventReceiver.h" #include "nsIAccessibleEventReceiver.h"
#include "nsMaiCache.h"
#include "nsMaiTopLevel.h" #include "nsMaiTopLevel.h"
#define MAI_TYPE_APP_ROOT (MAI_TYPE_ATK_OBJECT) #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 /* MaiAppRoot is the MaiObject class for Mozilla, the whole application. Only
* one instance of MaiAppRoot exists for one Mozilla instance. And the one * one instance of MaiAppRoot exists for one Mozilla instance. And the one
* should be created when Mozilla Startup (with accessibility feature * should be created when Mozilla Startup (with accessibility feature
@ -77,12 +66,9 @@ public:
virtual guint GetNSAccessibleUniqueID(); virtual guint GetNSAccessibleUniqueID();
gboolean AddMaiTopLevel(MaiTopLevel *aToplevel); PRBool AddMaiTopLevel(MaiTopLevel *aToplevel);
gboolean RemoveMaiTopLevel(MaiTopLevel *aToplevel); PRBool RemoveMaiTopLevelByID(guint aID);
MaiTopLevel *FindMaiTopLevel(MaiTopLevel *aToplevel); PRBool LookupTopLevelID(guint aID);
MaiTopLevel *FindMaiTopLevel(nsIAccessible *aToplevel);
MaiCache *GetCache(void);
public: public:
/* virtual functions for MaiObject */ /* virtual functions for MaiObject */
virtual AtkObject *GetAtkObject(void); virtual AtkObject *GetAtkObject(void);
@ -96,9 +82,6 @@ public:
virtual MaiObject *RefChild(gint aChildIndex); virtual MaiObject *RefChild(gint aChildIndex);
private: private:
GList *mTopLevelList; GList *mTopLevelList;
TopLevelItem *FindTopLevelItem(nsIAccessible *aAccess);
MaiCache *mMaiCache;
}; };
#endif /* __MAI_APP_ROOT_H__ */ #endif /* __MAI_APP_ROOT_H__ */

Просмотреть файл

@ -45,123 +45,179 @@ MaiCache::MaiCache()
{ {
/* cache index always point to the last item */ /* cache index always point to the last item */
mCacheIndex = -1; mCacheIndex = -1;
for (int index = 0; index < MAI_CACHE_SIZE; index++) { for (int index = 0; index < MAI_CACHE_SIZE; index++)
mCache[index].uid = 0; mCache[index]= 0;
mCache[index].maiObject = NULL;
}
} }
MaiCache::~MaiCache() MaiCache::~MaiCache()
{ {
AtkObject *tmpAtkObj = NULL; MaiObject *maiObj = NULL;
for (int index = 0; index < MAI_CACHE_SIZE; index++) { for (int index = 0; index < MAI_CACHE_SIZE; index++) {
if (mCache[index].maiObject && mCache[index].uid != 0) { if ((maiObj = MaiHashTable::Lookup(mCache[index]))) {
tmpAtkObj = mCache[index].maiObject->GetAtkObject(); MAI_LOG_DEBUG(("Mai Cache: de-caching, uid=0x%x, maiObj=0x%x \n",
MAI_LOG_DEBUG(("Mai Cache: de-caching, maiAtkObj=0x%x, ref=%d\ mCache[index], maiObj));
maiObj=0x%x, uid=%x\n", (guint)tmpAtkObj, mCache[index] = 0;
G_OBJECT(tmpAtkObj)->ref_count, g_object_unref(maiObj->GetAtkObject());
(guint)mCache[index].maiObject, mCache[index].uid));
g_object_unref(tmpAtkObj);
mCache[index].uid = 0;
mCache[index].maiObject = NULL;
} }
} }
} }
/* more advanced replacing algorithm can be employed for performance PRBool
* later in MaiCache::Add
*/
gboolean
MaiCache::Add(MaiObject *aMaiObj) MaiCache::Add(MaiObject *aMaiObj)
{ {
g_return_val_if_fail(aMaiObj != NULL, FALSE); g_return_val_if_fail(aMaiObj != NULL, PR_FALSE);
// different nsIAccessible object can have the same ID,
// but we deem them equal for accessible user. guint uid = aMaiObj->GetNSAccessibleUniqueID();
if (Fetch(aMaiObj)) { NS_ASSERTION((uid > 0), "Invalid nsAccessible ID");
MAI_LOG_DEBUG(("Mai Cache: already in Cache: aMaiObj=0x%x, uid=%x\n", if (uid < 0)
(guint)aMaiObj, aMaiObj->GetNSAccessibleUniqueID())); return PR_FALSE;
return TRUE;
}
gint counter = 0; gint counter = 0;
/* try to find a vacant place */ /* if it has been in cache */
while (counter < MAI_CACHE_SIZE) { while (counter < MAI_CACHE_SIZE) {
counter++; ++counter;
mCacheIndex = (++mCacheIndex) % MAI_CACHE_SIZE; mCacheIndex = (++mCacheIndex) % MAI_CACHE_SIZE;
if ((mCache[mCacheIndex].maiObject == NULL) && if ((mCache[mCacheIndex] == uid))
(mCache[mCacheIndex].uid == 0)) 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; break;
} }
/* if fail to find a vacant place, remove the old */ /* if fail to find a vacant place, remove an old one*/
AtkObject *tmpAtkObj = NULL;
if (counter >= MAI_CACHE_SIZE) { if (counter >= MAI_CACHE_SIZE) {
mCacheIndex = (++mCacheIndex) % MAI_CACHE_SIZE; mCacheIndex = (++mCacheIndex) % MAI_CACHE_SIZE;
tmpAtkObj = mCache[mCacheIndex].maiObject->GetAtkObject(); MaiObject *tmpMaiObj = MaiHashTable::Lookup(mCache[mCacheIndex]);
MAI_LOG_DEBUG(("Mai Cache: de-caching, maiAtkObj=0x%x, ref=%d \ NS_ASSERTION(tmpMaiObj, "Fail to lookup from hash table");
maiObj=0x%x, uid=%x\n", (guint)tmpAtkObj,
G_OBJECT(tmpAtkObj)->ref_count, MAI_LOG_DEBUG(("Mai Cache: de-caching, uid=0x%x, maiObj=0x%x \n",
(guint)mCache[mCacheIndex].maiObject, mCache[mCacheIndex], tmpMaiObj));
(guint)mCache[mCacheIndex].uid));
MAI_LOG_DEBUG(("Mai Cache: added in %d, replace", mCacheIndex)); MAI_LOG_DEBUG(("Mai Cache: added in %d, replace", mCacheIndex));
g_object_unref(tmpAtkObj); g_object_unref(tmpMaiObj->GetAtkObject());
} }
else else
MAI_LOG_DEBUG(("Mai Cache: added in %d, vacant", mCacheIndex)); MAI_LOG_DEBUG(("Mai Cache: added in %d, vacant", mCacheIndex));
g_object_ref(aMaiObj->GetAtkObject()); g_object_ref(aMaiObj->GetAtkObject());
mCache[mCacheIndex].uid = aMaiObj->GetNSAccessibleUniqueID(); mCache[mCacheIndex] = uid;
mCache[mCacheIndex].maiObject = aMaiObj;
MAI_LOG_DEBUG(("Mai Cache: Add in Cache, aMaiObj=0x%x, uid=%x\n", 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) nsMaiHashTable
{ *************************************/
g_return_val_if_fail(aMaiObj != NULL, FALSE);
guint uid = aMaiObj->GetNSAccessibleUniqueID();
for (int index = 0; index < MAI_CACHE_SIZE; index++) { PLHashTable *MaiHashTable::mMaiObjectHashTable = NULL;
if (mCache[index].uid == uid && mCache[index].maiObject) { PRBool MaiHashTable::mInitialized = PR_FALSE;
g_object_unref(mCache[index].maiObject->GetAtkObject());
mCache[index].uid = 0; static PLHashNumber IntHashKey(PRInt32 key);
mCache[index].maiObject = NULL;
return TRUE; #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 void
are equal. So the Fetch(guint uid) is the base for all the other Fetchs MaiHashTable::Destroy()
*/
MaiObject *
MaiCache::Fetch(guint uid)
{ {
for (int index = 0; index < MAI_CACHE_SIZE; index++) { if (mInitialized && mMaiObjectHashTable) {
if (mCache[index].uid == uid)
return mCache[index].maiObject; 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 * 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 * MaiObject *
MaiCache::Fetch(nsIAccessible *aAccess) MaiHashTable::Lookup(nsIAccessible *aAcc)
{ {
return Fetch(GetNSAccessibleUniqueID(aAccess)); return Lookup(::GetNSAccessibleUniqueID(aAcc));
} }
MaiObject * PLHashNumber
MaiCache::Fetch(AtkObject *aAtkObj) IntHashKey(PRInt32 key)
{ {
MAI_CHECK_ATK_OBJECT_RETURN_VAL_IF_FAIL(aAtkObj, NULL); return PLHashNumber(key);
return Fetch(MAI_ATK_OBJECT(aAtkObj)->maiObject);
} }
#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 */

Просмотреть файл

@ -42,13 +42,21 @@
#ifndef __MAI_CACHE_H__ #ifndef __MAI_CACHE_H__
#define __MAI_CACHE_H__ #define __MAI_CACHE_H__
#include "plhash.h"
#include "nsMaiObject.h" #include "nsMaiObject.h"
struct MaiCacheItem ////////////////////////////////////////////////////////////////
{ // Class MaiCache
guint uid; // ----------------------
MaiObject *maiObject; //
}; // 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 class MaiCache
{ {
@ -56,17 +64,29 @@ public:
MaiCache(); MaiCache();
~MaiCache(); ~MaiCache();
gboolean Add(MaiObject *aMaiObj); PRBool Add(MaiObject *aMaiObj);
gboolean Remove(MaiObject *aMaiObj);
MaiObject *Fetch(guint uid);
MaiObject *Fetch(MaiObject *aMaiObj);
MaiObject *Fetch(nsIAccessible *aAccess);
MaiObject *Fetch(AtkObject *aAtkObj);
private: private:
enum { MAI_CACHE_SIZE = 10 }; enum { MAI_CACHE_SIZE = 10 };
MaiCacheItem mCache [MAI_CACHE_SIZE]; guint mCache[MAI_CACHE_SIZE];
gint mCacheIndex; 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__ */ #endif /* __MAI_CACHE_H__ */

Просмотреть файл

@ -156,8 +156,7 @@ MaiHyperlink::GetObject(gint aLinkIndex)
if (NS_FAILED(rv) || !accObj) if (NS_FAILED(rv) || !accObj)
return NULL; return NULL;
/* ??? when the new one get freed? */ MaiWidget *maiObj = MaiWidget::CreateAndCache(accObj);
MaiWidget *maiObj = new MaiWidget(accObj);
return maiObj; return maiObj;
} }

Просмотреть файл

@ -344,7 +344,7 @@ MaiInterfaceTable::GetSummary()
gint gint
MaiInterfaceTable::GetSelectedColumns(gint **aSelected) MaiInterfaceTable::GetSelectedColumns(gint **aSelected)
{ {
MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, NULL); MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, 0);
PRUint32 size = 0; PRUint32 size = 0;
PRInt32 *columns = NULL; PRInt32 *columns = NULL;
@ -358,7 +358,7 @@ MaiInterfaceTable::GetSelectedColumns(gint **aSelected)
NS_ASSERTION(atkColumns, "Fail to get memory for columns"); NS_ASSERTION(atkColumns, "Fail to get memory for columns");
//copy //copy
for (int index = 0; index < size; ++index) for (PRUint32 index = 0; index < size; ++index)
atkColumns[index] = NS_STATIC_CAST(gint, columns[index]); atkColumns[index] = NS_STATIC_CAST(gint, columns[index]);
nsMemory::Free(columns); nsMemory::Free(columns);
@ -369,7 +369,7 @@ MaiInterfaceTable::GetSelectedColumns(gint **aSelected)
gint gint
MaiInterfaceTable::GetSelectedRows(gint **aSelected) MaiInterfaceTable::GetSelectedRows(gint **aSelected)
{ {
MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, NULL); MAI_IFACE_RETURN_VAL_IF_FAIL(accessIface, 0);
PRUint32 size = 0; PRUint32 size = 0;
PRInt32 *rows = NULL; PRInt32 *rows = NULL;
@ -383,7 +383,7 @@ MaiInterfaceTable::GetSelectedRows(gint **aSelected)
NS_ASSERTION(atkRows, "Fail to get memory for rows"); NS_ASSERTION(atkRows, "Fail to get memory for rows");
//copy //copy
for (int index = 0; index < size; ++index) for (PRUint32 index = 0; index < size; ++index)
atkRows[index] = NS_STATIC_CAST(gint, rows[index]); atkRows[index] = NS_STATIC_CAST(gint, rows[index]);
nsMemory::Free(rows); nsMemory::Free(rows);

Просмотреть файл

@ -40,6 +40,8 @@
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "nsMaiObject.h" #include "nsMaiObject.h"
#include "nsMaiUtil.h"
#include "nsMaiCache.h"
#include "nsIAccessibleEventListener.h" #include "nsIAccessibleEventListener.h"
#include "nsString.h" #include "nsString.h"
@ -139,6 +141,7 @@ MaiObject::MaiObject(nsIAccessible *aAcc)
#endif #endif
MAI_LOG_DEBUG(("====MaiObject creating this=0x%x,total =%d= created\n", MAI_LOG_DEBUG(("====MaiObject creating this=0x%x,total =%d= created\n",
(unsigned int)this, num_created_mai_object)); (unsigned int)this, num_created_mai_object));
} }
MaiObject::~MaiObject() MaiObject::~MaiObject()
@ -323,6 +326,9 @@ finalizeCB(GObject *aObj)
MaiObject *maiObject = MAI_ATK_OBJECT(aObj)->maiObject; MaiObject *maiObject = MAI_ATK_OBJECT(aObj)->maiObject;
MAI_LOG_DEBUG(("====release MaiAtkObject=0x%x, MaiObject=0x%x\n", MAI_LOG_DEBUG(("====release MaiAtkObject=0x%x, MaiObject=0x%x\n",
(guint)aObj, (guint)maiObject)); (guint)aObj, (guint)maiObject));
MaiHashTable::Remove(maiObject);
maiObject->Finalize(); maiObject->Finalize();
// never call MaiObject later // never call MaiObject later
@ -385,14 +391,7 @@ refChildCB(AtkObject *aObj, gint aChildIndex)
if (!childObject) if (!childObject)
return NULL; return NULL;
AtkObject *childAtkObj = childObject->GetAtkObject(); return childObject->GetAtkObject();
if (childAtkObj) {
g_object_ref(childAtkObj);
if (!childAtkObj->accessible_parent)
//this will addref parent
atk_object_set_parent(childAtkObj, aObj);
}
return childAtkObj;
} }
gint gint

Просмотреть файл

@ -88,31 +88,74 @@ MaiTopLevel::~MaiTopLevel()
receiver->RemoveAccessibleEventListener(); 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 NS_IMETHODIMP
MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible, MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
AccessibleEventData * aEventData) AccessibleEventData * aEventData)
{ {
MaiWidget *pMaiObject; nsresult rv = NS_ERROR_FAILURE;
MaiWidget *pMaiObject = NULL;
AtkTableChange * pAtkTableChange; AtkTableChange * pAtkTableChange;
MAI_LOG_DEBUG(("\n\nReceived event: aEvent=%u, obj=0x%x, data=0x%x \n", MAI_LOG_DEBUG(("\n\nReceived event: aEvent=%u, obj=0x%x, data=0x%x \n",
aEvent, aAccessible, aEventData)); aEvent, aAccessible, aEventData));
if (mAccessible == aAccessible) pMaiObject = CreateMaiWidgetFor(aAccessible);
pMaiObject = this;
else
pMaiObject = CreateMaiWidgetFor(aAccessible);
if (!pMaiObject) { if (!pMaiObject) {
MAI_LOG_DEBUG(("\n\nFail to Create MaiObject for obj=0x%x\n", MAI_LOG_DEBUG(("\n\nFail to Create MaiObject for obj=0x%x\n",
aAccessible)); aAccessible));
return NS_ERROR_FAILURE; return NS_ERROR_OUT_OF_MEMORY;
} }
MaiObject *oldMaiObj = NULL, *newMaiObj = NULL;
switch (aEvent) { switch (aEvent) {
case nsIAccessibleEventListener::EVENT_FOCUS: case nsIAccessibleEventListener::EVENT_FOCUS:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n"));
atk_focus_tracker_notify(ATK_OBJECT(pMaiObject->GetAtkObject())); atk_focus_tracker_notify(ATK_OBJECT(pMaiObject->GetAtkObject()));
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_STATE_CHANGE: case nsIAccessibleEventListener::EVENT_STATE_CHANGE:
@ -121,7 +164,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
MAI_LOG_DEBUG(("\n\nReceived: EVENT_STATE_CHANGE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_STATE_CHANGE\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
pAtkStateChange = NS_REINTERPRET_CAST(AtkStateChange *, aEventData); 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()), atk_object_notify_state_change(ATK_OBJECT(pMaiObject->GetAtkObject()),
atkState, pAtkStateChange->enable); atkState, pAtkStateChange->enable);
rv = NS_OK;
break; break;
/* /*
@ -150,37 +194,42 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_PROPERTY_CHANGE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_PROPERTY_CHANGE\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
pAtkPropChange = NS_REINTERPRET_CAST(AtkPropertyChange *, aEventData); pAtkPropChange = NS_REINTERPRET_CAST(AtkPropertyChange *, aEventData);
values.property_name = pAtkPropertyNameArray[pAtkPropChange->type]; values.property_name = pAtkPropertyNameArray[pAtkPropChange->type];
MAI_LOG_DEBUG(("\n\nthe type of EVENT_ATK_PROPERTY_CHANGE: %d\n\n", MAI_LOG_DEBUG(("\n\nthe type of EVENT_ATK_PROPERTY_CHANGE: %d\n\n",
pAtkPropChange->type)); pAtkPropChange->type));
switch (pAtkPropChange->type) { switch (pAtkPropChange->type) {
case PROP_TABLE_CAPTION: case PROP_TABLE_CAPTION:
case PROP_TABLE_SUMMARY: case PROP_TABLE_SUMMARY:
MaiObject *aOldMaiObj, *aNewMaiObj;
if (pAtkPropChange->oldvalue) if (pAtkPropChange->oldvalue)
aOldMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST oldMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST
(nsIAccessible *, (nsIAccessible *,
pAtkPropChange->oldvalue)); pAtkPropChange->oldvalue));
if (pAtkPropChange->newvalue) if (pAtkPropChange->newvalue)
aNewMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST newMaiObj = CreateMaiWidgetFor(NS_REINTERPRET_CAST
(nsIAccessible *, (nsIAccessible *,
pAtkPropChange->newvalue)); pAtkPropChange->newvalue));
if (!aOldMaiObj || !aNewMaiObj ) if (oldMaiObj && newMaiObj) {
return NS_ERROR_FAILURE; 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; break;
case PROP_TABLE_COLUMN_DESCRIPTION: case PROP_TABLE_COLUMN_DESCRIPTION:
@ -191,6 +240,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
g_value_set_int(&values.new_value, g_value_set_int(&values.new_value,
*NS_REINTERPRET_CAST(gint *, *NS_REINTERPRET_CAST(gint *,
pAtkPropChange->newvalue)); pAtkPropChange->newvalue));
rv = NS_OK;
break; break;
//Perhaps need more cases in the future //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_set_pointer (&values.old_value, pAtkPropChange->oldvalue);
g_value_init (&values.new_value, G_TYPE_POINTER); g_value_init (&values.new_value, G_TYPE_POINTER);
g_value_set_pointer (&values.new_value, pAtkPropChange->newvalue); g_value_set_pointer (&values.new_value, pAtkPropChange->newvalue);
rv = NS_OK;
} }
if (NS_SUCCEEDED(rv))
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
g_strconcat("property_change::", g_strconcat("property_change::",
values.property_name), values.property_name),
&values, NULL); &values, NULL);
break; break;
@ -212,6 +263,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_SELECTION_CHANGE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_SELECTION_CHANGE\n"));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"selection_changed"); "selection_changed");
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TEXT_CHANGE: 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")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_CHANGE\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
pAtkTextChange = NS_REINTERPRET_CAST(AtkTextChange *, aEventData); pAtkTextChange = NS_REINTERPRET_CAST(AtkTextChange *, aEventData);
g_signal_emit_by_name (ATK_OBJECT(pMaiObject->GetAtkObject()), 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", "text_changed::insert":"text_changed::delete",
pAtkTextChange->start, pAtkTextChange->start,
pAtkTextChange->length); pAtkTextChange->length);
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TEXT_SELECTION_CHANGE: case nsIAccessibleEventListener::EVENT_ATK_TEXT_SELECTION_CHANGE:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_SELECTION_CHANGE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_SELECTION_CHANGE\n"));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"text_selection_changed"); "text_selection_changed");
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TEXT_CARET_MOVE: case nsIAccessibleEventListener::EVENT_ATK_TEXT_CARET_MOVE:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_CARET_MOVE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TEXT_CARET_MOVE\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
MAI_LOG_DEBUG(("\n\nCaret postion: %d", *(gint *)aEventData )); MAI_LOG_DEBUG(("\n\nCaret postion: %d", *(gint *)aEventData ));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"text_caret_moved", "text_caret_moved",
// Curent caret position // Curent caret position
*(gint *)aEventData); *(gint *)aEventData);
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TABLE_MODEL_CHANGE: case nsIAccessibleEventListener::EVENT_ATK_TABLE_MODEL_CHANGE:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_MODEL_CHANGE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_MODEL_CHANGE\n"));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"model_changed"); "model_changed");
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_INSERT: case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_INSERT:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_INSERT\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_INSERT\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData);
@ -266,12 +322,13 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
pAtkTableChange->index, pAtkTableChange->index,
// The number of the inserted // The number of the inserted
pAtkTableChange->count); pAtkTableChange->count);
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_DELETE: case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_DELETE:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_DELETE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_DELETE\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData);
@ -281,18 +338,20 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
pAtkTableChange->index, pAtkTableChange->index,
// The number of the deleted // The number of the deleted
pAtkTableChange->count); pAtkTableChange->count);
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_REORDER: case nsIAccessibleEventListener::EVENT_ATK_TABLE_ROW_REORDER:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_REORDER\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_ROW_REORDER\n"));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"row_reordered"); "row_reordered");
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_INSERT: case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_INSERT:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_INSERT\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_INSERT\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData);
@ -302,12 +361,13 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
pAtkTableChange->index, pAtkTableChange->index,
// The number of the inserted // The number of the inserted
pAtkTableChange->count); pAtkTableChange->count);
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_DELETE: case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_DELETE:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_DELETE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_DELETE\n"));
if (!aEventData) if (!aEventData)
return NS_ERROR_FAILURE; break;
pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData); pAtkTableChange = NS_REINTERPRET_CAST(AtkTableChange *, aEventData);
@ -317,18 +377,21 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
pAtkTableChange->index, pAtkTableChange->index,
// The number of the deleted // The number of the deleted
pAtkTableChange->count); pAtkTableChange->count);
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_REORDER: case nsIAccessibleEventListener::EVENT_ATK_TABLE_COLUMN_REORDER:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_REORDER\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_TABLE_COLUMN_REORDER\n"));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"column_reordered"); "column_reordered");
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_ATK_VISIBLE_DATA_CHANGE: case nsIAccessibleEventListener::EVENT_ATK_VISIBLE_DATA_CHANGE:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_VISIBLE_DATA_CHANGE\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_ATK_VISIBLE_DATA_CHANGE\n"));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"visible_data_changed"); "visible_data_changed");
rv = NS_OK;
break; break;
// Is a superclass of ATK event children_changed // Is a superclass of ATK event children_changed
@ -352,6 +415,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
pAtkChildrenChange->index, pAtkChildrenChange->index,
ATK_OBJECT(childMaiObject->GetAtkObject()), ATK_OBJECT(childMaiObject->GetAtkObject()),
NULL); NULL);
g_object_unref(childMaiObject->GetAtkObject());
} }
else { else {
g_signal_emit_by_name (ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name (ATK_OBJECT(pMaiObject->GetAtkObject()),
@ -359,6 +423,7 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
-1, NULL, NULL); -1, NULL, NULL);
} }
rv = NS_OK;
break; break;
/* /*
@ -372,12 +437,14 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
atk_focus_tracker_notify(ATK_OBJECT(pMaiObject->GetAtkObject())); atk_focus_tracker_notify(ATK_OBJECT(pMaiObject->GetAtkObject()));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"selection_changed"); "selection_changed");
rv = NS_OK;
break; break;
case nsIAccessibleEventListener::EVENT_MENUEND: case nsIAccessibleEventListener::EVENT_MENUEND:
MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUEND\n")); MAI_LOG_DEBUG(("\n\nReceived: EVENT_MENUEND\n"));
g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()), g_signal_emit_by_name(ATK_OBJECT(pMaiObject->GetAtkObject()),
"selection_changed"); "selection_changed");
rv = NS_OK;
break; break;
default: default:
@ -386,7 +453,9 @@ MaiTopLevel::HandleEvent(PRUint32 aEvent, nsIAccessible *aAccessible,
break; 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); 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 */ /* static */
AtkStateType AtkStateType
MaiTopLevel::TranslateAState(PRUint32 aAccState) MaiTopLevel::TranslateAState(PRUint32 aAccState)

Просмотреть файл

@ -56,6 +56,7 @@ class MaiTopLevel: public MaiWidget, public nsIAccessibleEventListener
public: public:
MaiTopLevel(nsIAccessible *aAcc); MaiTopLevel(nsIAccessible *aAcc);
virtual ~MaiTopLevel(); virtual ~MaiTopLevel();
static MaiTopLevel * Create(nsIAccessible *aAcc);
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// nsIAccessibleEventListener // nsIAccessibleEventListener

Просмотреть файл

@ -42,12 +42,17 @@
#include <stdlib.h> #include <stdlib.h>
#include "nsMaiUtil.h" #include "nsMaiUtil.h"
#include "nsMaiCache.h"
#include "nsMaiAppRoot.h" #include "nsMaiAppRoot.h"
static gboolean mai_shutdown(void); static gboolean mai_shutdown(void);
static void mai_delete_root(void); static void mai_delete_root(void);
static MaiAppRoot *mai_create_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); static void mai_util_class_init(MaiUtilClass *klass);
/* atkutil.h */ /* atkutil.h */
@ -305,6 +310,9 @@ mai_init(MaiHook **aMaiHook)
/* Initialize the MAI Utility class */ /* Initialize the MAI Utility class */
g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL)); g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL));
MaiHashTable::Init();
mai_create_cache();
return TRUE; return TRUE;
} }
@ -323,6 +331,9 @@ mai_shutdown(void)
sMaiHook.RemoveTopLevelAccessible = NULL; sMaiHook.RemoveTopLevelAccessible = NULL;
mai_delete_root(); mai_delete_root();
mai_delete_cache();
MaiHashTable::Destroy();
return TRUE; return TRUE;
} }
@ -338,6 +349,7 @@ mai_create_root(void)
} }
if (!sRootAccessible) { if (!sRootAccessible) {
sRootAccessible = new MaiAppRoot(); sRootAccessible = new MaiAppRoot();
MaiHashTable::Add(sRootAccessible);
NS_ASSERTION(sRootAccessible, "Fail to create MaiAppRoot"); NS_ASSERTION(sRootAccessible, "Fail to create MaiAppRoot");
/* initialize the MAI hook /* initialize the MAI hook
@ -363,23 +375,41 @@ void
mai_delete_root(void) mai_delete_root(void)
{ {
if (sRootAccessible) { if (sRootAccessible) {
delete sRootAccessible; g_object_unref(sRootAccessible->GetAtkObject());
sRootAccessible = NULL; sRootAccessible = NULL;
} }
} }
/* return the reference of MaiCache. /* return the reference of MaiCache.
*/ */
static MaiCache *sMaiCache = NULL;
MaiCache * MaiCache *
mai_get_cache(void) mai_create_cache(void)
{ {
if (!mai_initialized) { if (!mai_initialized) {
return NULL; return NULL;
} }
MaiAppRoot *root = mai_get_root(); if (!sMaiCache) {
if (root) sMaiCache = new MaiCache();
return root->GetCache(); NS_ASSERTION(sMaiCache, "Fail to create MaiCache");
return NULL; }
return sMaiCache;
}
MaiCache *
mai_get_cache(void)
{
return sMaiCache;
}
void
mai_delete_cache(void)
{
if (sMaiCache) {
delete sMaiCache;
sMaiCache = NULL;
}
} }
gboolean gboolean
@ -387,35 +417,16 @@ mai_add_toplevel_accessible(nsIAccessible *toplevel)
{ {
g_return_val_if_fail(toplevel != NULL, TRUE); g_return_val_if_fail(toplevel != NULL, TRUE);
#if 1
MaiAppRoot *root; MaiAppRoot *root;
root = mai_get_root(); root = mai_get_root();
if (!root) if (!root)
return FALSE; 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); g_return_val_if_fail(mai_top_level != NULL, PR_FALSE);
gboolean res = root->AddMaiTopLevel(mai_top_level); gboolean res = root->AddMaiTopLevel(mai_top_level);
/* root will add ref for itself use */
g_object_unref(mai_top_level->GetAtkObject()); g_object_unref(mai_top_level->GetAtkObject());
return res; 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 gboolean
@ -426,8 +437,9 @@ mai_remove_toplevel_accessible(nsIAccessible *toplevel)
MaiAppRoot *root; MaiAppRoot *root;
root = mai_get_root(); root = mai_get_root();
if (root) { if (root) {
MaiTopLevel *mai_top_level = root->FindMaiTopLevel(toplevel); guint uid = ::GetNSAccessibleUniqueID(toplevel);
return root->RemoveMaiTopLevel(mai_top_level); gboolean res = root->RemoveMaiTopLevelByID(uid);
return res;
} }
else else
return FALSE; return FALSE;

Просмотреть файл

@ -77,7 +77,7 @@ struct _MaiUtilClass
}; };
#define MAI_VERSION "0.0.6" #define MAI_VERSION "0.0.6"
#define MAI_NAME "MAI-Mozilla Atk Interface" #define MAI_NAME "mozilla"
MaiAppRoot *mai_get_root(void); MaiAppRoot *mai_get_root(void);
MaiCache *mai_get_cache(void); MaiCache *mai_get_cache(void);

Просмотреть файл

@ -60,6 +60,7 @@
#include "nsMaiInterfaceValue.h" #include "nsMaiInterfaceValue.h"
#include "nsMaiUtil.h" #include "nsMaiUtil.h"
#include "nsMaiCache.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -120,6 +121,69 @@ MaiWidget::~MaiWidget()
g_hash_table_destroy(mChildren); 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 #ifdef MAI_LOGGING
void void
MaiWidget::DumpMaiObjectInfo(gint aDepth) MaiWidget::DumpMaiObjectInfo(gint aDepth)
@ -167,61 +231,12 @@ MaiWidget::GetMaiInterface(MaiInterfaceType aIfaceType)
return mMaiInterface[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 void
MaiWidget::ChildrenChange(AtkChildrenChange *event) MaiWidget::ChildrenChange(AtkChildrenChange *event)
{ {
MaiWidget *maiChild; MaiWidget *maiChild;
if (event && event->child && if (event && event->child &&
(maiChild = CreateAndCache(event->child))) { (maiChild = Create(event->child))) {
//update the specified child, but now use the easiest way. //update the specified child, but now use the easiest way.
g_hash_table_destroy(mChildren); g_hash_table_destroy(mChildren);
mChildren = g_hash_table_new(g_direct_hash, NULL); mChildren = g_hash_table_new(g_direct_hash, NULL);
@ -407,7 +422,7 @@ MaiWidget::GetParent(void)
return NULL; return NULL;
/* create a maiWidget for parent */ /* create a maiWidget for parent */
return CreateAndCache(accParent); return Create(accParent);
} }
gint gint
@ -430,16 +445,19 @@ MaiWidget::RefChild(gint aChildIndex)
MaiObject *maiChild = NULL; MaiObject *maiChild = NULL;
guint uid; guint uid;
// look in cache first
MaiCache *maiCache = mai_get_cache(); // look in hashtable first
if (maiCache) { uid = GetChildUniqueID(aChildIndex);
uid = GetChildUniqueID(aChildIndex); if (uid > 0 && (maiChild = MaiHashTable::Lookup(uid))) {
if (uid > 0 && (maiChild = maiCache->Fetch(uid))) { MAI_LOG_DEBUG(("got child 0x%x from hash table\n", (guint)maiChild));
MAI_LOG_DEBUG(("got child 0x%x from cache\n", (guint)maiChild)); g_object_ref(maiChild->GetAtkObject());
return maiChild;
} //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 // nsIAccessible child index starts with 1
gint accChildIndex = 1; gint accChildIndex = 1;
nsCOMPtr<nsIAccessible> accChild = NULL; nsCOMPtr<nsIAccessible> accChild = NULL;
@ -459,16 +477,12 @@ MaiWidget::RefChild(gint aChildIndex)
// user, since they point to the same dom node. // user, since they point to the same dom node.
// So, maybe the it has been cached. // So, maybe the it has been cached.
uid = ::GetNSAccessibleUniqueID(accChild); 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 // update children uid list
SetChildUniqueID(aChildIndex, uid); SetChildUniqueID(aChildIndex, uid);
maiChild = Create(accChild);
//this will addref parent
atk_object_set_parent(maiChild->GetAtkObject(), GetAtkObject());
return maiChild; return maiChild;
} }
@ -552,7 +566,7 @@ MaiWidget::SetChildUniqueID(gint aChildIndex, guint aChildUid)
void void
classInitCB(AtkObjectClass *aClass) 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); parent_class = g_type_class_peek_parent(aClass);

Просмотреть файл

@ -85,6 +85,8 @@ class MaiWidget: public MaiObject
public: public:
MaiWidget(nsIAccessible *aAcc); MaiWidget(nsIAccessible *aAcc);
virtual ~MaiWidget(); virtual ~MaiWidget();
static MaiWidget *Create(nsIAccessible *aAcc);
#ifdef MAI_LOGGING #ifdef MAI_LOGGING
virtual void DumpMaiObjectInfo(int aDepth); virtual void DumpMaiObjectInfo(int aDepth);
#endif #endif