Applied patch 1, to provide a syborg specific minigui oby file.
Need to compare this with the "stripped" version currently in the tree.
This supplied version applies for Nokia builds, but need to repeat the
test for SF builds to see if pruning is needed, or if the file needs to
be device-specific.
// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Window server event queue handling
//
//
#include "EVQUEUE.H"
#include "server.h"
#include "wstop.h"
#include "panics.h"
#include "pointer.h"
#include "wstraces.h"
GLREF_D CDebugLogBase *wsDebugLog;
#if defined(_DEBUG)
#define __CHECK_QUEUE() CheckQueue()
#define __ZAP_EVENTS(pointer,len) ZapEvents(pointer,len)
#define __ZAP_EVENT(pointer) ZapEvent(pointer)
#else
#define __CHECK_QUEUE()
#define __ZAP_EVENTS(pointer,len)
#define __ZAP_EVENT(pointer)
#endif
const TInt ECopyBufSize=4;
TDblQue<CEventQueue> CEventQueue::iQueueList(_FOFF(CEventQueue,iLink));
TWsEvent *CEventQueue::iGlobalEventQueue=NULL;
TInt CEventQueue::iGlobalEventQueueSize=0;
TInt CEventQueue::iNumConnections=0;
RMutex CEventQueue::iMutex;
TWsEvent CEventQueue::iNullEvent;
// CEventBase
CEventBase::~CEventBase()
{
if (!iEventMsg.IsNull() && CWsTop::ShuttingDown())
{
iEventMsg.Complete(KErrServerTerminated);
}
}
CEventBase::CEventBase(CWsClient *aOwner) : iWsOwner(aOwner)
{
}
void CEventBase::SignalEvent(TInt aCode)
{
if (wsDebugLog)
wsDebugLog->SignalEvent(iWsOwner->ConnectionHandle());
iEventMsg.Complete(aCode);
iEventSignalledState|=EEventFlagSignalled;
}
inline TBool CEventBase::IsEventCancelled()
{
return (iEventSignalledState & EEventFlagCancelled);
}
void CEventBase::CancelRead()
//
// If there is an outstanding read cancel it.
//
{
if (!iEventMsg.IsNull())
{
iEventMsg.Complete(KErrCancel);
}
iEventSignalledState|=EEventFlagCancelled;
}
void CEventBase::GetData(TAny *aData, TInt aLen)
{
if (!(iEventSignalledState&EEventFlagSignalled))
{
iWsOwner->PPanic(EWservPanicUnsignalledEventData);
}
iEventSignalledState&=~EEventFlagSignalled;
CWsClient::ReplyBuf(aData,aLen);
}
void CEventBase::EventReadyCheck()
//
// Queue a read of an event notification
//
{
if ((iEventSignalledState&EEventFlagSignalled && !(iEventSignalledState&EEventFlagCancelled)) || !iEventMsg.IsNull())
{
iWsOwner->PPanic(EWservPanicReadOutstanding);
}
}
void CEventBase::EventReady(const RMessagePtr2& aEventMsg)
{
EventReadyCheck();
iEventMsg=aEventMsg;
}
// CEventQueue - Queue organisation functions
#if defined(_DEBUG)
void CEventQueue::CheckQueue()
{
TDblQueIter<CEventQueue> iter(iQueueList);
CEventQueue *qptr;
iter.SetToFirst();
while((qptr=iter++)!=NULL)
{
WS_ASSERT_DEBUG(qptr->iQueueSize>=0 && qptr->iQueueSize<=iGlobalEventQueueSize, EWsPanicCheckEventQueue);
WS_ASSERT_DEBUG(qptr->iQueueSize==0 || qptr->iHead<qptr->iQueueSize, EWsPanicCheckEventQueue);
WS_ASSERT_DEBUG(qptr->iCount<=qptr->iQueueSize, EWsPanicCheckEventQueue);
WS_ASSERT_DEBUG(qptr->iEventPtr>=iGlobalEventQueue && qptr->iEventPtr<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicCheckEventQueue);
}
for(TInt index=0;index<iCount;index++)
{
TWsEvent *ev=EventPtr(index);
WS_ASSERT_DEBUG(ev->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
}
}
void CEventQueue::ZapEvent(TWsEvent *aTarget)
{
aTarget->SetType(EEventMarkInvalid);
aTarget->SetHandle(555);
}
void CEventQueue::ZapEvents(TWsEvent *aTarget, TInt aLen)
{
for(TInt index=0;index<aLen;index++)
ZapEvent(aTarget+index);
}
#endif
void CEventQueue::EventCopy(TWsEvent *aTarget, TWsEvent *aSource, TInt aNumEvents)
{
WS_ASSERT_DEBUG(aTarget>=iGlobalEventQueue, EWsPanicEventQueueCopy);
WS_ASSERT_DEBUG((aTarget+aNumEvents)<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicEventQueueCopy);
Mem::Copy(aTarget,aSource,aNumEvents*sizeof(TWsEvent));
}
TInt CEventQueue::RequiredQueueSize(TInt aNumConnections)
{
return(aNumConnections*EMinQueueSize+EMaxQueueSize+EExtraQueueSize);
}
/**
Adjust the Global Queue Size.
@param aNewSize the size for event queue.
*/
void CEventQueue::AdjustQueueSizeL(TInt aNewSize)
{
TWsEvent* oldQ=iGlobalEventQueue;
if (aNewSize < iGlobalEventQueueSize)
{
// Re-alloc wont move the cell down to a lower address, this means once this cell is
// high up in memory it may never move down again, thus wasting loads of global heap space.
const CEventQueue* last=iQueueList.Last();
if ((last->iEventPtr + last->iQueueSize) >= (iGlobalEventQueue + aNewSize))
{
return;
}
TInt allocSize = aNewSize * sizeof(TWsEvent);
iGlobalEventQueue=static_cast<TWsEvent*>(User::AllocL(allocSize));
Mem::Copy(iGlobalEventQueue,oldQ,allocSize);
User::Free(oldQ);
}
else
{
iGlobalEventQueue = static_cast<TWsEvent*>(User::ReAllocL(iGlobalEventQueue, aNewSize * sizeof(TWsEvent)));
}
__ZAP_EVENTS(iGlobalEventQueue + iGlobalEventQueueSize, aNewSize - iGlobalEventQueueSize);
iGlobalEventQueueSize = aNewSize;
// coverity[use_after_free]
TInt diff=(reinterpret_cast<TInt8*>(iGlobalEventQueue)-reinterpret_cast<TInt8*>(oldQ));
if (diff)
{
TDblQueIter<CEventQueue> iter(iQueueList);
CEventQueue* qptr;
while((qptr=iter++)!=NULL)
{
qptr->iEventPtr=reinterpret_cast<TWsEvent*>(reinterpret_cast<TInt8*>(qptr->iEventPtr)+diff);
}
}
}
void CEventQueue::AddQueueL()
{
Wait();
if ((iNumConnections%EQueueGranularity)==0)
{
const TInt newSize = RequiredQueueSize(iNumConnections + EQueueGranularity);
TRAPD(err,AdjustQueueSizeL(newSize));
if (err!=KErrNone)
{
__CHECK_QUEUE();
Signal();
User::Leave(err);
}
}
iNumConnections++;
if (iQueueList.IsEmpty())
iEventPtr=iGlobalEventQueue;
else
{
CEventQueue *qptr=iQueueList.Last();
iEventPtr=qptr->iEventPtr+qptr->iQueueSize;
}
iQueueList.AddLast(*this);
//Initialize the queue size to at least EMinQueueSize
//Check the queue by doing standard queue compression.
TBool isExpanded = ETrue;
do {isExpanded = Expand(EEventPriorityLow);} while ((iQueueSize < EMinQueueSize) && isExpanded);
while (iQueueSize < EMinQueueSize)
{
//Cannot get enough spaces by doing standard queue compression,
//try to grow the global queue.
TInt sizeRequired = EMinQueueSize - iQueueSize;
const TInt newSize = iGlobalEventQueueSize + sizeRequired;
TRAPD(err, AdjustQueueSizeL(newSize));
if (err != KErrNone)
{
//Cannot get enough spaces by growing global queue.
//try to purge the oldest events from inactive clients.
TInt numEventCleared = PurgeInactiveEvents(sizeRequired);
if (numEventCleared == 0)
{
__CHECK_QUEUE();
Signal();
User::Leave(err);
}
}
while (doExpand(ECompressNoPurge)) {};
}
__CHECK_QUEUE();
Signal();
}
void CEventQueue::RemoveQueue()
{
Wait();
if (iEventPtr) // If this is still NULL this class hasn't been linked into the Q list
{
__ZAP_EVENTS(iEventPtr, iQueueSize);
iLink.Deque();
if (--iNumConnections==0)
{
User::Free(iGlobalEventQueue);
iGlobalEventQueue=NULL;
iGlobalEventQueueSize=0;
}
else if ((iNumConnections%EQueueGranularity)==0)
{
TDblQueIter<CEventQueue> iter(iQueueList);
CEventQueue* qptr=iter++;
qptr->Compress(ECompressNoPurge);
while((qptr=iter++)!=NULL)
{
qptr->SqueezeDown();
}
const TInt newSize = RequiredQueueSize(iNumConnections);
TRAP_IGNORE(AdjustQueueSizeL(newSize));
// Can easily leave as we need to allocate the new smaller queue before freeing
// the old queue. But if it does it doesn't matter as we'll simply be left with
// a larger than necessary buffer until the next realloc
}
iCount=0;
}
__CHECK_QUEUE();
Signal();
}
void CEventQueue::IncreaseQueueSize(TInt aNumSpaces)
{
if ((iQueueSize+aNumSpaces)>EMaxQueueSize)
aNumSpaces=EMaxQueueSize-iQueueSize;
EventCopy(iEventPtr+iHead+aNumSpaces, iEventPtr+iHead, iQueueSize-iHead);
__ZAP_EVENTS(iEventPtr+iHead, aNumSpaces);
iQueueSize+=aNumSpaces;
iHead=(iHead+aNumSpaces)%iQueueSize;
}
TBool CEventQueue::Expand(TWservEventPriorities aPriority)
{
if (iQueueSize==EMaxQueueSize)
{
if (aPriority==EEventPriorityHigh)
{
Purge();
if (iCount<iQueueSize)
return(ETrue); // Success!
}
}
else if (doExpand(ECompressNoPurge) ||
doExpand(ECompressPurge1) ||
(aPriority==EEventPriorityHigh && doExpand(ECompressPurge2)))
return(ETrue);
return(EFalse); // Failure
}
TBool CEventQueue::doExpand(TCompressMode aCompressMode)
{
TDblQueIter<CEventQueue> iter(iQueueList);
iter.SetToLast();
CEventQueue* qptr=NULL;
TInt spare=0;
// while loop from last queue till current queue, moving all queues up
// to get all the space from between them
while((qptr=iter)!=this)
{
spare=qptr->SqueezeUp();
if (spare==0)
qptr->Compress(aCompressMode);
iter--;
}
// current queue, if we have space then expand the same and return
spare=FollowingGap();
if (spare>0)
{
IncreaseQueueSize(spare);
__CHECK_QUEUE();
return(ETrue);
}
// while loop from current queue till first queue, looking for a gap
// between queues and using the first one it finds
iter--;
TInt expanded=0;
while((qptr=iter)!=NULL)
{
expanded=qptr->SqueezeUp();
if (expanded>0)
{
return MoveDownAndExpand(iter, expanded);
}
else
qptr->Compress(aCompressMode);
iter--;
}
// Even by doing all the above if we did not find space then check if first
// queue has some space before it. If so then make use of it and movedown all the
// queue till the current queue and then use the space for expansion
iter.SetToFirst();
qptr=iter;
if (qptr->iEventPtr>iGlobalEventQueue)
{
return MoveDownAndExpand(iter, qptr->iEventPtr-iGlobalEventQueue);
}
__CHECK_QUEUE();
return(EFalse); // Failed to expand enough room
}
// This function moves the queue down by given amount and repeats this until
// the current queue and then expand the same
TBool CEventQueue::MoveDownAndExpand(TDblQueIter<CEventQueue> &aIter, TInt aExpand)
{
CEventQueue* qptr=NULL;
FOREVER
{
qptr=aIter++;
qptr->MoveDown(aExpand);
if (qptr==this)
{
IncreaseQueueSize(aExpand);
__CHECK_QUEUE();
break;
}
}
return ETrue;
}
void CEventQueue::MoveDown(TInt aMove)
{
if (!aMove)
{
return;
}
EventCopy(iEventPtr-aMove,iEventPtr,iQueueSize);
iEventPtr-=aMove;
}
/*void CEventQueue::LogUpDownEvents(TChar aChar)
{
TWsEvent *event;
TBuf<128> buf;
buf.Zero();
buf.Append(aChar);
buf.Append('#');
buf.Append('#');
TBool some=EFalse;
TInt index;
for (index=0;index<iCount;index++)
{
event=EventPtr(index);
if (event->Type()==EEventPointer)
{
if (event->Pointer()->iType==TPointerEvent::EButton1Down
|| event->Pointer()->iType==TPointerEvent::EButton1Up)
{
some=ETrue;
if (event->Pointer()->iType==TPointerEvent::EButton1Down)
buf.Append('D');
else
buf.Append('U');
buf.AppendNum(index);
}
}
}
if (wsDebugLog)
wsDebugLog->MiscMessage(ELogImportant,buf);
}*/
void CEventQueue::Purge()
{
// Purgable events are:
// Pointer Up/Down pairs
// Pointer moves & drags
// Key messages
// Key Up/Down pairs
// Key Ups if not foreground connection
// Focus lost/gained pairs
//
// Events that must no be purged
// Key ups for foreground connections queue
// Lone pointer ups, must be delivered to match preceeding pointer down
// Lone focus lost/gained messages
//
TWsEvent *event;
TWsEvent *event2;
TInt index2;
TInt index=iCount;
while(index>0)
{
event=EventPtr(--index);
switch(event->Type())
{
case EEventPassword:
break;
case EEventMarkInvalid:
#if defined(_DEBUG)
WS_PANIC_DEBUG(EWsPanicCheckEventQueue);
#endif
case EEventNull:
case EEventKey:
case EEventPointerEnter:
case EEventPointerExit:
case EEventDragDrop:
breakLoopAndRemoveEvent:
RemoveEvent(index);
return;
case EEventKeyUp:
if (iQueueList.First()!=this)
goto breakLoopAndRemoveEvent;
break;
case EEventKeyDown:
if (iQueueList.First()!=this)
goto breakLoopAndRemoveEvent;
for (index2=index+1;index2<iCount;index2++)
{
event2=EventPtr(index2);
if (event2->Type()==EEventKeyUp && event2->Key()->iScanCode==event->Key()->iScanCode)
{
*event2=iNullEvent;
goto breakLoopAndRemoveEvent;
}
}
break;
case EEventModifiersChanged:
for (index2=index;index2>0;)
{
event2=EventPtr(--index2);
if (event2->Type()==EEventModifiersChanged)
{
event->ModifiersChanged()->iChangedModifiers|=event2->ModifiersChanged()->iChangedModifiers;
index=index2;
goto breakLoopAndRemoveEvent;
}
}
break;
case EEventPointerBufferReady:
CWsPointerBuffer::DiscardPointerMoveBuffer(event->Handle());
goto breakLoopAndRemoveEvent;
case EEventFocusLost:
case EEventFocusGained:
if ((index+1)<iCount)
{
event2=EventPtr(index+1);
if (event2->Type()==EEventFocusLost || event2->Type()==EEventFocusGained)
{
*event2=iNullEvent;
goto breakLoopAndRemoveEvent;
}
}
break;
case EEventSwitchOn:
if ((index+1)<iCount && EventPtr(index+1)->Type()==EEventSwitchOn)
goto breakLoopAndRemoveEvent;
break;
case EEventPointer:
{
TPointerEvent::TType upType;
switch(event->Pointer()->iType)
{
case TPointerEvent::EDrag:
case TPointerEvent::EMove:
case TPointerEvent::EButtonRepeat:
case TPointerEvent::ESwitchOn:
goto breakLoopAndRemoveEvent;
case TPointerEvent::EButton1Down:
upType=TPointerEvent::EButton1Up;
goto purgeDownUp;
case TPointerEvent::EButton2Down:
upType=TPointerEvent::EButton2Up;
goto purgeDownUp;
case TPointerEvent::EButton3Down:
upType=TPointerEvent::EButton3Up;
purgeDownUp: for (index2=index+1;index2<iCount;index2++)
{
event2=EventPtr(index2);
if (event2->Type()==EEventPointer && event2->Handle()==event->Handle() && event2->Pointer()->iType==upType)
{
*event2=iNullEvent;
goto breakLoopAndRemoveEvent;
}
}
WsPointer::UnmatchedDownPurged(upType, event->Handle());
goto breakLoopAndRemoveEvent;
case TPointerEvent::EButton1Up:
case TPointerEvent::EButton2Up:
case TPointerEvent::EButton3Up:
break;
}
}
break;
}
}
}
void CEventQueue::PurgePointerEvents()
{
TWsEvent *event;
TWsEvent *event2;
TInt index2;
TInt index=iCount;
while(index>0)
{
event=EventPtr(--index);
switch(event->Type())
{
case EEventPointerBufferReady:
CWsPointerBuffer::DiscardPointerMoveBuffer(event->Handle());
RemoveEvent(index);
break;
case EEventPointer:
{
TPointerEvent::TType upType;
switch(event->Pointer()->iType)
{
case TPointerEvent::EDrag:
case TPointerEvent::EMove:
case TPointerEvent::EButtonRepeat:
case TPointerEvent::ESwitchOn:
RemoveEvent(index);
break;
case TPointerEvent::EButton1Down:
upType=TPointerEvent::EButton1Up;
goto purgeDownUp2;
case TPointerEvent::EButton2Down:
upType=TPointerEvent::EButton2Up;
goto purgeDownUp2;
case TPointerEvent::EButton3Down:
upType=TPointerEvent::EButton3Up;
purgeDownUp2: for (index2=index+1;index2<iCount;index2++)
{
event2=EventPtr(index2);
if (event2->Type()==EEventPointer && event2->Handle()==event->Handle() && event2->Pointer()->iType==upType)
{
*event2=iNullEvent;
goto purgedUp;
}
}
WsPointer::UnmatchedDownPurged(upType, event->Handle());
purgedUp: RemoveEvent(index);
break;
case TPointerEvent::EButton1Up:
case TPointerEvent::EButton2Up:
case TPointerEvent::EButton3Up:
break;
}
}
break;
}
}
}
/**
Purge requested number of oldest events from inactive event queue.
@param aSizeRequired the total events required to be cleared.
@return The number of events cleared.
*/
TInt CEventQueue::PurgeInactiveEvents(const TInt& aSizeRequired)
{
TInt numEventsCleared = 0;
CEventQueue* qptr;
TBool isRemoved;
do {
TDblQueIter<CEventQueue> iter(iQueueList);
isRemoved = EFalse;
while ((qptr = iter++) != NULL && (aSizeRequired > numEventsCleared))
{
if ((qptr->IsEventCancelled() || (qptr->iEventMsg.IsNull() && !qptr->iEventSignalledState)) &&
(qptr->iQueueSize > EMinQueueSize))
{
// we have a client that is not listening with a size larger than min queue size.
// so lets remove it's oldest event until the number of removed events meet the requirement.
qptr->RemoveEvent(0);
numEventsCleared++;
isRemoved = ETrue;
}
}
} while ((aSizeRequired > numEventsCleared) && isRemoved);
return numEventsCleared;
}
void CEventQueue::Compress(TCompressMode aCompressMode)
{
//
// The different purge modes are
//
// ECompressNoPurge, // Don't purge anything
// ECompressPurge1, // Don't purge foreground queue
// ECompressPurge2, // Purge all queues
//
if (aCompressMode==ECompressPurge2 ||
(this!=iQueueList.First() && aCompressMode==ECompressPurge1))
Purge();
TInt compress=iQueueSize-(iCount>EMinQueueSize?iCount:EMinQueueSize);
if (compress>0)
{
compress=(compress+1)/2; // Compress half the free space in the queue
TWsEvent *head=EventPtr(0);
TWsEvent *tail=EventPtr(iCount);
if (head>tail)
{
EventCopy(iEventPtr+compress,iEventPtr,tail-iEventPtr);
iHead-=compress;
}
else
{
EventCopy(iEventPtr+compress,head,iCount);
iHead=0;
}
iEventPtr+=compress;
iQueueSize-=compress;
}
}
void CEventQueue::MoveUp(TInt aNumEvents)
{
if (!aNumEvents)
{
return;
}
EventCopy(iEventPtr+aNumEvents,iEventPtr,iQueueSize);
iEventPtr+=aNumEvents;
}
TInt CEventQueue::FollowingGap() const
{
TDblQueIter<CEventQueue> iter(iQueueList);
CEventQueue *qptr;
iter.Set(*(CEventQueue *)this);
iter++;
TWsEvent *end;
if ((qptr=iter)!=NULL)
end=qptr->iEventPtr;
else
end=iGlobalEventQueue+iGlobalEventQueueSize;
return(end-(iEventPtr+iQueueSize));
}
TInt CEventQueue::SqueezeUp()
{
TInt gap=FollowingGap();
MoveUp(gap);
return(gap);
}
void CEventQueue::SqueezeDown()
{
TDblQueIter<CEventQueue> iter(iQueueList);
iter.Set(*this);
iter--;
CEventQueue *qptr=iter;
if (qptr!=NULL)
{
Compress(ECompressNoPurge);
TInt gap=qptr->FollowingGap();
MoveDown(gap);
}
}
void CEventQueue::MoveToFront()
{
if (this==iQueueList.First())
return;
Wait();
CEventQueue *qptr;
TInt gap=0;
TDblQueIter<CEventQueue> iter(iQueueList);
iter.SetToLast();
while((qptr=iter--)!=NULL)
{
if (gap<iQueueSize)
qptr->Compress(ECompressNoPurge);
gap=qptr->SqueezeUp();
}
if (gap>=iQueueSize)
EventCopy(iGlobalEventQueue,iEventPtr,iQueueSize);
else
{
EventCopy(iGlobalEventQueue,iEventPtr,gap);
iEventPtr+=gap;
TWsEvent copyBuf[ECopyBufSize]; // temp buffer, can copy upto ECopyBufSize events at a time
TInt eventsToGo=iQueueSize-gap;
iQueueSize=gap;
do
{
TInt copy=Min(eventsToGo,ECopyBufSize);
Mem::Copy(©Buf[0],iEventPtr,copy*sizeof(TWsEvent));
iter.Set(*this);
iter--;
while((qptr=iter--)!=NULL)
qptr->MoveUp(copy);
EventCopy(iGlobalEventQueue+iQueueSize,©Buf[0],copy);
iQueueSize+=copy;
eventsToGo-=copy;
iEventPtr+=copy;
} while(eventsToGo>0);
}
iEventPtr=iGlobalEventQueue;
this->iLink.Deque();
iQueueList.AddFirst(*this);
__CHECK_QUEUE();
Signal();
}
// CEventQueue
CEventQueue::CEventQueue(CWsClient *aOwner) : CEventBase(aOwner)
{
__DECLARE_NAME(_S("CEventQueue"));
}
CEventQueue::~CEventQueue()
{
RemoveQueue();
}
void CEventQueue::InitStaticsL()
{
User::LeaveIfError(iMutex.CreateLocal());
}
void CEventQueue::DeleteStaticsL()
{
iMutex.Close();
}
void CEventQueue::ConstructL()
{
AddQueueL();
Mem::FillZ(&iNullEvent,sizeof(iNullEvent));
}
TWsEvent *CEventQueue::EventPtr(TInt index)
{
return(iEventPtr+((iHead+index)%iQueueSize));
}
TBool CEventQueue::QueueEvent(const TWsEvent &event)
{
TWservEventPriorities priority=EEventPriorityLow;
#ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP
if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff ||
event.Type()==EEventKeySwitchOff || event.Type()==EEventRestartSystem)
#else
if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || event.Type()==EEventKeySwitchOff)
#endif
{
priority=EEventPriorityHigh;
}
return(QueueEvent(event,priority));
}
TBool CEventQueue::CheckRoom()
//
// If the queue is full and room is created return ETrue
//
{
TBool ret=EFalse;
Wait();
if (iCount==iQueueSize && Expand(EEventPriorityHigh))
ret=ETrue;
Signal();
return(ret);
}
TBool CEventQueue::QueueEvent(const TWsEvent &event, TWservEventPriorities aPriority)
//
// Queue an event, returns ETrue if queued or delivered, EFalse if the queue was full.
//
{
WS_TRACE_SERVER_QUEUEEVENT();
TBool ret=ETrue;
Wait();
if (iCount==iQueueSize && !Expand(aPriority))
ret=EFalse;
else
{
if (!iEventMsg.IsNull())
{
SignalEvent();
}
*EventPtr(iCount++)=event;
}
Signal();
return(ret);
}
TBool CEventQueue::QueueEvent(TUint32 aTarget, TInt aEvent)
{
TWsEvent event;
event.SetType(aEvent);
event.SetHandle(aTarget);
event.SetTimeNow();
return(QueueEvent(event));
}
void CEventQueue::UpdateLastEvent(const TWsEvent &event)
{
WS_ASSERT_DEBUG(iCount>0, EWsPanicQueueUpdateCount);
Mem::Copy(EventPtr(iCount-1)->EventData(),event.EventData(),TWsEvent::EWsEventDataSize);
Signal();
}
void CEventQueue::GetData()
//
// If there is an outstanding event in the queue, reply with it's data and remove it from the Q
//
{
if (iCount>0)
{
WS_ASSERT_DEBUG((iEventPtr+iHead)->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
CEventBase::GetData(iEventPtr+iHead,sizeof(*iEventPtr));
__ZAP_EVENT(iEventPtr+iHead);
iHead=(iHead+1)%iQueueSize;
iCount--;
}
else
CEventBase::GetData(&iNullEvent,sizeof(iNullEvent));
}
void CEventQueue::EventReady(const RMessagePtr2& aEventMsg)
//
// Queue a read of an event notification
//
{
EventReadyCheck();
Wait();
iEventMsg=aEventMsg;
if (iCount>0)
SignalEvent();
Signal();
}
void CEventQueue::RemoveEvent(TInt index)
//
// Remove event 'index' in the queue, this event MUST exist in the queue
//
{
WS_ASSERT_DEBUG(index < iCount, EWsPanicCheckEventQueue);
iCount--;
for(;index<iCount;index++)
*EventPtr(index)= *EventPtr(index+1);
__ZAP_EVENT(EventPtr(iCount));
}
const TWsEvent *CEventQueue::PeekLastEvent()
//
// Return a read only pointer to the last event in the queue (or NULL if no event)
//
{
if (iCount==0)
return(NULL);
return(EventPtr(iCount-1));
}
void CEventQueue::Wait()
{
iMutex.Wait();
}
void CEventQueue::Signal()
{
iMutex.Signal();
}
void CEventQueue::WalkEventQueue(EventQueueWalk aFunc, TAny *aFuncParam)
{
Wait();
restart:
for (TInt index=0;index<iCount;index++)
{
TWsEvent *event=EventPtr(index);
switch((aFunc)(aFuncParam,event))
{
case EEventQueueWalkDeleteEvent:
RemoveEvent(index--);
case EEventQueueWalkOk:
break;
case EEventQueueWalkRestart:
goto restart;
}
}
Signal();
}