Mozilla/mozilla/xpcom/proxy/src/nsProxyEventObject.cpp
dougt%netscape.com 5ba4026869 Changes and bug fixes suggested by brendan.
git-svn-id: svn://10.0.0.236/trunk@32979 18797224-902f-48f8-a5cc-f745e15eee43
1999-05-27 21:25:43 +00:00

308 lines
7.1 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsProxyEvent.h"
#include "nsProxyObjectManager.h"
#include "nsProxyEventPrivate.h"
#include "nsHashtable.h"
#include "nsIInterfaceInfoManager.h"
#include "xptcall.h"
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// nsProxyEventObject
//
//////////////////////////////////////////////////////////////////////////////////////////////////
nsProxyEventObject*
nsProxyEventObject::GetNewOrUsedProxy(PLEventQueue *destQueue,
nsISupports *aObj,
REFNSIID aIID)
{
nsProxyEventObject* proxy = NULL;
nsProxyEventObject* root = NULL;
nsProxyEventClass* clazz = nsProxyEventClass::GetNewOrUsedClass(aIID);
if(!clazz)
return NULL;
nsISupports* rootObject;
// always find the native root
if(NS_FAILED(aObj->QueryInterface(nsISupports::GetIID(), (void**)&rootObject)))
return NULL;
/* find in our hash table */
nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap();
if (realToProxyMap == nsnull)
{
if(clazz)
NS_RELEASE(clazz);
return nsnull;
}
nsVoidKey key(rootObject);
if(realToProxyMap->Exists(&key))
{
root = (nsProxyEventObject*) realToProxyMap->Get(&key);
proxy = root->Find(aIID);
if(proxy)
{
NS_ADDREF(proxy);
goto return_wrapper;
}
}
else
{
// build the root proxy
if (aObj == rootObject)
{
// the root will do double duty as the interface wrapper
proxy = root = new nsProxyEventObject(destQueue, aObj, clazz, nsnull);
if(root)
realToProxyMap->Put(&key, root);
goto return_wrapper;
}
else
{
// just a root proxy
nsProxyEventClass* rootClazz = nsProxyEventClass::GetNewOrUsedClass(nsISupports::GetIID());
if(!rootClazz)
{
goto return_wrapper;
}
root = new nsProxyEventObject(destQueue, rootObject, rootClazz, nsnull);
NS_RELEASE(rootClazz);
if(!root)
{
goto return_wrapper;
}
realToProxyMap->Put(&key, root);
}
}
// at this point we have a root and may need to build the specific proxy
NS_ASSERTION(root,"bad root");
NS_ASSERTION(clazz,"bad clazz");
if(!proxy)
{
proxy = new nsProxyEventObject(destQueue, aObj, clazz, root);
if(!proxy)
{
goto return_wrapper;
}
}
proxy->mNext = root->mNext;
root->mNext = proxy;
return_wrapper:
if(clazz)
NS_RELEASE(clazz);
// Since we do not want to extra references, we will release the rootObject.
//
// There are one or more references to aObj which is passed in. When we create
// a new proxy object via nsProxyEventObject(), that will addRef the aObj. Because
// we QI addref to insure that we have a nsISupports ptr, its refcount goes up by one.
// here we will decrement that.
//
if (rootObject)
NS_RELEASE(rootObject);
return proxy;
}
nsProxyEventObject::nsProxyEventObject(PLEventQueue *destQueue,
nsISupports* aObj,
nsProxyEventClass* aClass,
nsProxyEventObject* root)
: mClass(aClass),
mNext(NULL)
{
mRoot = (root ? root : this);
mProxyObject = new nsProxyObject(destQueue, aObj);
NS_INIT_REFCNT();
NS_ADDREF_THIS();
NS_ADDREF(aClass);
}
nsProxyEventObject::~nsProxyEventObject()
{
NS_PRECONDITION(0 == mRefCnt, "refcounting error");
if(mRoot == this && GetClass())
{
nsVoidKey key(this);
nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
nsHashtable *realToProxyMap = manager->GetRealObjectToProxyObjectMap();
if (realToProxyMap == nsnull)
{
realToProxyMap->Remove(&key);
}
}
if (mProxyObject != nsnull)
delete mProxyObject;
NS_RELEASE(mClass);
if(mNext)
NS_DELETEXPCOM(mNext); // cascaded delete
}
NS_IMETHODIMP
nsProxyEventObject::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if(NULL == aInstancePtr)
{
NS_PRECONDITION(0, "null pointer");
return NS_ERROR_NULL_POINTER;
}
return mClass->DelegatedQueryInterface(this, aIID, aInstancePtr);
}
nsrefcnt
nsProxyEventObject::AddRef(void)
{
NS_PRECONDITION(mRoot, "bad root");
if(1 == ++mRefCnt && mRoot && mRoot != this)
NS_ADDREF(mRoot);
return mRefCnt;
}
nsrefcnt
nsProxyEventObject::Release(void)
{
NS_PRECONDITION(mRoot, "bad root");
NS_PRECONDITION(0 != mRefCnt, "dup release");
if(0 == --mRefCnt)
{
if(mRoot == this)
{
NS_DELETEXPCOM(this); // cascaded delete
}
else
{
mRoot->Release();
}
return 0;
}
return mRefCnt;
}
nsProxyEventObject*
nsProxyEventObject::Find(REFNSIID aIID)
{
if(aIID.Equals(nsISupports::GetIID()))
return mRoot;
nsProxyEventObject* cur = mRoot;
do
{
if(aIID.Equals(GetIID()))
return cur;
} while(NULL != (cur = cur->mNext));
return NULL;
}
NS_IMETHODIMP
nsProxyEventObject::GetInterfaceInfo(nsIInterfaceInfo** info)
{
NS_ASSERTION(GetClass(), "proxy without class");
NS_ASSERTION(GetClass()->GetInterfaceInfo(), "proxy class without interface");
if(!(*info = GetClass()->GetInterfaceInfo()))
return NS_ERROR_UNEXPECTED;
NS_ADDREF(*info);
return NS_OK;
}
NS_IMETHODIMP
nsProxyEventObject::CallMethod(PRUint16 methodIndex,
const nsXPTMethodInfo* info,
nsXPTCMiniVariant * params)
{
uint8 paramCount = info->GetParamCount();
nsXPTCVariant *fullParam = (nsXPTCVariant*)malloc(sizeof(nsXPTCVariant) * paramCount);
for (int index = 0; index < paramCount; index++)
{
fullParam[index].flags = 0;
fullParam[index].val = params[index].val;
}
nsresult rv = mProxyObject->Post(methodIndex, paramCount, fullParam);
if (fullParam)
free( (void*) fullParam);
return rv;
}