зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
75d069ac37
Коммит
6f7d1e2855
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -42,12 +42,17 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<nsIAccessible> 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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче