Committing the changes to support the new nsIEventQueue interface and
nested queues in the event queue service. git-svn-id: svn://10.0.0.236/trunk@30290 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -17,15 +17,14 @@
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "prmon.h"
|
||||
#include "nsComponentManager.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsXPComFactory.h"
|
||||
|
||||
|
||||
static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID);
|
||||
|
||||
|
||||
|
||||
// XXX move to nsID.h or nsHashtable.h? (copied from nsComponentManager.cpp)
|
||||
class ThreadKey: public nsHashKey {
|
||||
private:
|
||||
@@ -50,6 +49,66 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/* This class is used with the EventQueueEntries to allow us to nest
|
||||
event queues */
|
||||
class EventQueueStack
|
||||
{
|
||||
public:
|
||||
EventQueueStack(EventQueueStack* next = NULL);
|
||||
~EventQueueStack();
|
||||
|
||||
nsIEventQueue* GetEventQueue();
|
||||
EventQueueStack* GetNext();
|
||||
void SetNext(EventQueueStack* aStack);
|
||||
|
||||
private:
|
||||
nsIEventQueue* mEventQueue;
|
||||
EventQueueStack* mNextQueue;
|
||||
};
|
||||
|
||||
static NS_DEFINE_IID(kIEventQueueIID, NS_IEVENTQUEUE_IID);
|
||||
static NS_DEFINE_IID(kEventQueueCID, NS_EVENTQUEUE_CID);
|
||||
|
||||
EventQueueStack::EventQueueStack(EventQueueStack* next)
|
||||
:mNextQueue(next)
|
||||
{
|
||||
// Create our thread queue using the component manager
|
||||
if (NS_FAILED(nsComponentManager::CreateInstance(kEventQueueCID, NULL, kIEventQueueIID,
|
||||
(void**)&mEventQueue))) {
|
||||
mEventQueue = NULL;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mEventQueue->Init()))
|
||||
mEventQueue = NULL;
|
||||
}
|
||||
|
||||
EventQueueStack::~EventQueueStack()
|
||||
{
|
||||
// Destroy our thread queue.
|
||||
NS_IF_RELEASE(mEventQueue);
|
||||
|
||||
if (mNextQueue)
|
||||
{
|
||||
delete mNextQueue;
|
||||
}
|
||||
}
|
||||
|
||||
nsIEventQueue* EventQueueStack::GetEventQueue()
|
||||
{
|
||||
NS_ADDREF(mEventQueue);
|
||||
return mEventQueue;
|
||||
}
|
||||
|
||||
EventQueueStack* EventQueueStack::GetNext()
|
||||
{
|
||||
return mNextQueue;
|
||||
}
|
||||
|
||||
void EventQueueStack::SetNext(EventQueueStack* aStack)
|
||||
{
|
||||
mNextQueue = aStack;
|
||||
}
|
||||
|
||||
/*
|
||||
* This class maintains the data associated with each entry in the EventQueue
|
||||
* service's hash table...
|
||||
@@ -66,10 +125,13 @@ public:
|
||||
// nsISupports interface...
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
PLEventQueue* GetEventQueue(void);
|
||||
nsIEventQueue* GetEventQueue(void);
|
||||
|
||||
void PushQueue(void);
|
||||
void PopQueue(void);
|
||||
|
||||
private:
|
||||
PLEventQueue* mEventQueue;
|
||||
EventQueueStack* mQueueStack;
|
||||
};
|
||||
|
||||
/* nsISupports interface implementation... */
|
||||
@@ -79,22 +141,42 @@ EventQueueEntry::EventQueueEntry()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
mEventQueue = PL_CreateNativeEventQueue("Thread event queue...", PR_GetCurrentThread());
|
||||
mQueueStack = new EventQueueStack();
|
||||
}
|
||||
|
||||
EventQueueEntry::~EventQueueEntry()
|
||||
{
|
||||
if (NULL != mEventQueue) {
|
||||
PL_DestroyEventQueue(mEventQueue);
|
||||
}
|
||||
// Delete our stack
|
||||
delete mQueueStack;
|
||||
}
|
||||
|
||||
PLEventQueue* EventQueueEntry::GetEventQueue(void)
|
||||
nsIEventQueue* EventQueueEntry::GetEventQueue(void)
|
||||
{
|
||||
return mEventQueue;
|
||||
// Return the current event queue on our stack.
|
||||
nsIEventQueue* answer = NULL;
|
||||
if (mQueueStack)
|
||||
answer = mQueueStack->GetEventQueue(); // This call addrefs the queue
|
||||
return answer;
|
||||
}
|
||||
|
||||
void EventQueueEntry::PushQueue(void)
|
||||
{
|
||||
// Make a new thread queue, connect it to our current stack, and then
|
||||
// set it to be the top of our stack.
|
||||
mQueueStack = new EventQueueStack(mQueueStack);
|
||||
}
|
||||
|
||||
void EventQueueEntry::PopQueue(void)
|
||||
{
|
||||
EventQueueStack* popped = mQueueStack;
|
||||
if (mQueueStack) {
|
||||
mQueueStack = mQueueStack->GetNext();
|
||||
popped->SetNext(NULL);
|
||||
}
|
||||
|
||||
// This will result in the queue being released.
|
||||
delete popped;
|
||||
}
|
||||
|
||||
class nsEventQueueServiceImpl : public nsIEventQueueService
|
||||
{
|
||||
@@ -107,7 +189,12 @@ public:
|
||||
// nsIEventQueueService interface...
|
||||
NS_IMETHOD CreateThreadEventQueue(void);
|
||||
NS_IMETHOD DestroyThreadEventQueue(void);
|
||||
NS_IMETHOD GetThreadEventQueue(PRThread* aThread, PLEventQueue** aResult);
|
||||
NS_IMETHOD GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult);
|
||||
|
||||
NS_IMETHOD CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult);
|
||||
|
||||
NS_IMETHOD PushThreadEventQueue(void);
|
||||
NS_IMETHOD PopThreadEventQueue(void);
|
||||
|
||||
#ifdef XP_MAC
|
||||
NS_IMETHOD ProcessEvents();
|
||||
@@ -211,9 +298,94 @@ nsEventQueueServiceImpl::DestroyThreadEventQueue(void)
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventQueueServiceImpl::CreateFromPLEventQueue(PLEventQueue* aPLEventQueue, nsIEventQueue** aResult)
|
||||
{
|
||||
// Create our thread queue using the component manager
|
||||
nsresult rv;
|
||||
nsIEventQueue* aQueue;
|
||||
if (NS_FAILED(rv = nsComponentManager::CreateInstance(kEventQueueCID, NULL, kIEventQueueIID,
|
||||
(void**)&aQueue))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv = aQueue->InitFromPLQueue(aPLEventQueue))) {
|
||||
NS_IF_RELEASE(aQueue);
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aResult = aQueue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, PLEventQueue** aResult)
|
||||
nsEventQueueServiceImpl::PushThreadEventQueue()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
ThreadKey key(PR_GetCurrentThread());
|
||||
EventQueueEntry* evQueueEntry;
|
||||
|
||||
/* Enter the lock which protects the EventQ hashtable... */
|
||||
PR_EnterMonitor(mEventQMonitor);
|
||||
|
||||
/* Only create one event queue per thread... */
|
||||
evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key);
|
||||
if (NULL == evQueueEntry) {
|
||||
evQueueEntry = new EventQueueEntry();
|
||||
if (NULL == evQueueEntry) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
mEventQTable->Put(&key, evQueueEntry);
|
||||
}
|
||||
else {
|
||||
// An entry was already present. We need to push a new
|
||||
// queue onto our stack.
|
||||
evQueueEntry->PushQueue();
|
||||
}
|
||||
|
||||
NS_ADDREF(evQueueEntry);
|
||||
|
||||
done:
|
||||
// Release the EventQ lock...
|
||||
PR_ExitMonitor(mEventQMonitor);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventQueueServiceImpl::PopThreadEventQueue(void)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
ThreadKey key(PR_GetCurrentThread());
|
||||
EventQueueEntry* evQueueEntry;
|
||||
|
||||
/* Enter the lock which protects the EventQ hashtable... */
|
||||
PR_EnterMonitor(mEventQMonitor);
|
||||
|
||||
evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key);
|
||||
if (NULL != evQueueEntry) {
|
||||
nsrefcnt refcnt;
|
||||
|
||||
NS_RELEASE2(evQueueEntry, refcnt);
|
||||
// Remove the entry from the hash table if this was the last reference...
|
||||
if (0 == refcnt) {
|
||||
mEventQTable->Remove(&key);
|
||||
}
|
||||
else {
|
||||
// We must be popping.
|
||||
evQueueEntry->PopQueue();
|
||||
}
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Release the EventQ lock...
|
||||
PR_ExitMonitor(mEventQMonitor);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, nsIEventQueue** aResult)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
EventQueueEntry* evQueueEntry;
|
||||
@@ -230,7 +402,7 @@ nsEventQueueServiceImpl::GetThreadEventQueue(PRThread* aThread, PLEventQueue** a
|
||||
|
||||
evQueueEntry = (EventQueueEntry*)mEventQTable->Get(&key);
|
||||
if (NULL != evQueueEntry) {
|
||||
*aResult = evQueueEntry->GetEventQueue();
|
||||
*aResult = evQueueEntry->GetEventQueue(); // Queue addrefing is done by this call.
|
||||
} else {
|
||||
// XXX: Need error code for requesting an event queue when none exists...
|
||||
*aResult = NULL;
|
||||
@@ -248,7 +420,13 @@ done:
|
||||
static PRBool EventDispatchingFunc(nsHashKey *aKey, void *aData, void* closure)
|
||||
{
|
||||
EventQueueEntry* entry = (EventQueueEntry*) aData;
|
||||
PL_ProcessPendingEvents( entry->GetEventQueue() );
|
||||
nsIEventQueue* eventQueue = entry->GetEventQueue();
|
||||
|
||||
if (eventQueue) {
|
||||
eventQueue->ProcessPendingEvents();
|
||||
NS_RELEASE(eventQueue);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user