windowing/windowserver/nga/SERVER/EVQUEUE.CPP
changeset 0 5d03bc08d59c
child 136 62bb7c97884c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Window server event queue handling
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "EVQUEUE.H"
       
    19 
       
    20 #include "server.h"
       
    21 #include "wstop.h"
       
    22 #include "panics.h"
       
    23 #include "pointer.h"
       
    24 #include "advancedpointereventhelper.h"
       
    25 
       
    26 GLREF_D CDebugLogBase* wsDebugLog;
       
    27 
       
    28 #if defined(_DEBUG)
       
    29 #define __CHECK_QUEUE() CheckQueue()
       
    30 #define __ZAP_EVENTS(pointer,len) ZapEvents(pointer,len)
       
    31 #define __ZAP_EVENT(pointer) ZapEvent(pointer)
       
    32 #else
       
    33 #define __CHECK_QUEUE()
       
    34 #define __ZAP_EVENTS(pointer,len)
       
    35 #define __ZAP_EVENT(pointer)
       
    36 #endif
       
    37 
       
    38 const TInt ECopyBufSize=4;
       
    39 
       
    40 TDblQue<CEventQueue> CEventQueue::iQueueList(_FOFF(CEventQueue,iLink));
       
    41 TWsEvent* CEventQueue::iGlobalEventQueue=NULL;
       
    42 TInt CEventQueue::iGlobalEventQueueSize=0;
       
    43 TInt CEventQueue::iNumConnections=0;
       
    44 RMutex CEventQueue::iMutex;
       
    45 TWsEvent CEventQueue::iNullEvent;
       
    46 
       
    47 // CEventBase
       
    48 
       
    49 CEventBase::~CEventBase()
       
    50 	{
       
    51 	if (!iEventMsg.IsNull() && CWsTop::ShuttingDown())
       
    52 		{
       
    53 		iEventMsg.Complete(KErrServerTerminated);
       
    54 		}
       
    55 	}
       
    56 
       
    57 CEventBase::CEventBase(CWsClient* aOwner) : iWsOwner(aOwner)
       
    58 	{
       
    59 	}
       
    60 
       
    61 void CEventBase::SignalEvent(TInt aCode)
       
    62 	{
       
    63 	if (wsDebugLog)
       
    64 		wsDebugLog->SignalEvent(iWsOwner->ConnectionHandle());
       
    65 	iEventMsg.Complete(aCode);
       
    66 	iEventSignalledState|=EEventFlagSignalled;
       
    67 	}
       
    68 
       
    69 inline TBool CEventBase::IsEventCancelled()
       
    70 	{
       
    71 	return (iEventSignalledState & EEventFlagCancelled);
       
    72 	}
       
    73 
       
    74 /**
       
    75 If there is an outstanding read cancel it.
       
    76 */
       
    77 void CEventBase::CancelRead()
       
    78 	{
       
    79 	if (!iEventMsg.IsNull())
       
    80 		{
       
    81 		iEventMsg.Complete(KErrCancel);
       
    82 		}
       
    83 	iEventSignalledState|=EEventFlagCancelled;
       
    84 	}
       
    85 
       
    86 void CEventBase::GetData(TAny* aData, TInt aLen)
       
    87 	{
       
    88 	if (!(iEventSignalledState&EEventFlagSignalled))
       
    89 		{
       
    90 		iWsOwner->PPanic(EWservPanicUnsignalledEventData);
       
    91 		}
       
    92 	iEventSignalledState&=~EEventFlagSignalled;
       
    93 	CWsClient::ReplyBuf(aData,aLen);
       
    94 	}
       
    95 
       
    96 /**
       
    97 Queue a read of an event notification
       
    98 */
       
    99 void CEventBase::EventReadyCheck()
       
   100 	{
       
   101 	if ((iEventSignalledState&EEventFlagSignalled && !(iEventSignalledState&EEventFlagCancelled)) || !iEventMsg.IsNull())
       
   102 		{
       
   103 		iWsOwner->PPanic(EWservPanicReadOutstanding);
       
   104 		}
       
   105 	}
       
   106 
       
   107 void CEventBase::EventReady(const RMessagePtr2& aEventMsg)
       
   108 	{
       
   109 	EventReadyCheck();
       
   110 	iEventMsg=aEventMsg;
       
   111 	}
       
   112 
       
   113 // CEventQueue - Queue organisation functions
       
   114 
       
   115 #if defined(_DEBUG)
       
   116 void CEventQueue::CheckQueue()
       
   117 	{
       
   118 	TDblQueIter<CEventQueue> iter(iQueueList);
       
   119 	CEventQueue* qptr;
       
   120 	iter.SetToFirst();
       
   121 	while((qptr=iter++)!=NULL)
       
   122 		{
       
   123 		WS_ASSERT_DEBUG(qptr->iQueueSize>=0 && qptr->iQueueSize<=iGlobalEventQueueSize, EWsPanicCheckEventQueue);
       
   124 		WS_ASSERT_DEBUG(qptr->iQueueSize==0 || qptr->iHead<qptr->iQueueSize, EWsPanicCheckEventQueue);
       
   125 		WS_ASSERT_DEBUG(qptr->iCount<=qptr->iQueueSize, EWsPanicCheckEventQueue);
       
   126 		WS_ASSERT_DEBUG(qptr->iEventPtr>=iGlobalEventQueue && qptr->iEventPtr<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicCheckEventQueue);
       
   127 		}
       
   128 	for(TInt index=0;index<iCount;index++)
       
   129 		{
       
   130 		TWsEvent* ev=EventPtr(index);
       
   131 		WS_ASSERT_DEBUG(ev->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
       
   132 		}
       
   133 	}
       
   134 
       
   135 void CEventQueue::ZapEvent(TWsEvent* aTarget)
       
   136 	{
       
   137 	aTarget->SetType(EEventMarkInvalid);
       
   138 	aTarget->SetHandle(555);
       
   139 	}
       
   140 
       
   141 void CEventQueue::ZapEvents(TWsEvent* aTarget, TInt aLen)
       
   142 	{
       
   143 	for(TInt index=0;index<aLen;index++)
       
   144 		ZapEvent(aTarget+index);
       
   145 	}
       
   146 
       
   147 #endif
       
   148 
       
   149 void CEventQueue::EventCopy(TWsEvent* aTarget, TWsEvent* aSource, TInt aNumEvents)
       
   150 	{
       
   151 	WS_ASSERT_DEBUG(aTarget>=iGlobalEventQueue, EWsPanicEventQueueCopy);
       
   152 	WS_ASSERT_DEBUG((aTarget+aNumEvents)<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicEventQueueCopy);
       
   153 	Mem::Copy(aTarget,aSource,aNumEvents*sizeof(TWsEvent));
       
   154 	}
       
   155 
       
   156 TInt CEventQueue::RequiredQueueSize(TInt aNumConnections)
       
   157 	{
       
   158 	return(aNumConnections*EMinQueueSize+EMaxQueueSize+EExtraQueueSize);
       
   159 	}
       
   160 
       
   161 /**
       
   162 Adjust the Global Queue Size.
       
   163 @param aNewSize the size for event queue. 
       
   164 */
       
   165 void CEventQueue::AdjustQueueSizeL(TInt aNewSize)
       
   166 	{
       
   167 	TWsEvent* oldQ=iGlobalEventQueue;
       
   168 	if (aNewSize < iGlobalEventQueueSize)
       
   169 		{
       
   170 		// Re-alloc wont move the cell down to a lower address, this means once this cell is
       
   171 		// high up in memory it may never move down again, thus wasting loads of global heap space.
       
   172 		const CEventQueue* last=iQueueList.Last();
       
   173 		if ((last->iEventPtr + last->iQueueSize) >= (iGlobalEventQueue + aNewSize))
       
   174 			{
       
   175 			return;
       
   176 			}
       
   177 		TInt allocSize = aNewSize * sizeof(TWsEvent);
       
   178 		iGlobalEventQueue=static_cast<TWsEvent*>(User::AllocL(allocSize));
       
   179 		Mem::Copy(iGlobalEventQueue,oldQ,allocSize);
       
   180 		User::Free(oldQ);
       
   181 		}
       
   182 	else
       
   183 		{
       
   184 		iGlobalEventQueue = static_cast<TWsEvent*>(User::ReAllocL(iGlobalEventQueue, aNewSize * sizeof(TWsEvent)));
       
   185 		}
       
   186 	__ZAP_EVENTS(iGlobalEventQueue + iGlobalEventQueueSize, aNewSize - iGlobalEventQueueSize); 
       
   187 	iGlobalEventQueueSize = aNewSize; 
       
   188 	// coverity[use_after_free]
       
   189 	TInt diff=(reinterpret_cast<TInt8*>(iGlobalEventQueue)-reinterpret_cast<TInt8*>(oldQ));
       
   190 	if (diff)
       
   191 		{
       
   192 		TDblQueIter<CEventQueue> iter(iQueueList);
       
   193 		CEventQueue* qptr;
       
   194 		while((qptr=iter++)!=NULL)
       
   195 			{
       
   196 			qptr->iEventPtr=reinterpret_cast<TWsEvent*>(reinterpret_cast<TInt8*>(qptr->iEventPtr)+diff);
       
   197 			}
       
   198 		}
       
   199 	}
       
   200 
       
   201 void CEventQueue::AddQueueL()
       
   202 	{
       
   203 	Wait();
       
   204 	if ((iNumConnections%EQueueGranularity)==0)
       
   205 		{
       
   206 		const TInt newSize = RequiredQueueSize(iNumConnections + EQueueGranularity);
       
   207 		TRAPD(err,AdjustQueueSizeL(newSize));
       
   208 		if (err!=KErrNone)
       
   209 			{
       
   210 			__CHECK_QUEUE();
       
   211 			Signal();
       
   212 			User::Leave(err);
       
   213 			}
       
   214 		}
       
   215 	iNumConnections++;
       
   216 	if (iQueueList.IsEmpty())
       
   217 		iEventPtr=iGlobalEventQueue;
       
   218 	else
       
   219 		{
       
   220 		CEventQueue* qptr=iQueueList.Last();
       
   221 		iEventPtr=qptr->iEventPtr+qptr->iQueueSize;
       
   222 		}
       
   223 	iQueueList.AddLast(*this);
       
   224 	
       
   225 	//Initialize the queue size to at least EMinQueueSize
       
   226 	//Check the queue by doing standard queue compression.
       
   227 	TBool isExpanded = ETrue;
       
   228 	do {isExpanded = Expand(EEventPriorityLow);} while ((iQueueSize < EMinQueueSize) && isExpanded);
       
   229 	while (iQueueSize < EMinQueueSize)
       
   230 		{
       
   231 		//Cannot get enough spaces by doing standard queue compression,
       
   232 		//try to grow the global queue.
       
   233 		TInt sizeRequired = EMinQueueSize - iQueueSize;
       
   234 		const TInt newSize = iGlobalEventQueueSize + sizeRequired;
       
   235 		TRAPD(err, AdjustQueueSizeL(newSize));
       
   236 		if (err != KErrNone)
       
   237 			{
       
   238 			//Cannot get enough spaces by growing global queue.
       
   239 			//try to purge the oldest events from inactive clients.				
       
   240 			TInt numEventCleared = PurgeInactiveEvents(sizeRequired);
       
   241 			if (numEventCleared == 0)
       
   242 				{
       
   243 				__CHECK_QUEUE();
       
   244 				Signal();
       
   245 				User::Leave(err);
       
   246 				}
       
   247 			}
       
   248 		while (doExpand(ECompressNoPurge)) {};
       
   249 		}
       
   250 	__CHECK_QUEUE();
       
   251 	Signal();
       
   252 	}
       
   253 
       
   254 void CEventQueue::RemoveQueue()
       
   255 	{
       
   256 	Wait();
       
   257 	if (iEventPtr)	// If this is still NULL this class hasn't been linked into the Q list
       
   258 		{
       
   259 		__ZAP_EVENTS(iEventPtr, iQueueSize);
       
   260 		iLink.Deque();
       
   261 		if (--iNumConnections==0)
       
   262 			{
       
   263 			User::Free(iGlobalEventQueue);
       
   264 			iGlobalEventQueue=NULL;
       
   265 			iGlobalEventQueueSize=0;
       
   266 			}
       
   267 		else if ((iNumConnections%EQueueGranularity)==0)
       
   268 			{
       
   269 			TDblQueIter<CEventQueue> iter(iQueueList);
       
   270 			CEventQueue* qptr=iter++;
       
   271 			qptr->Compress(ECompressNoPurge);
       
   272 			while((qptr=iter++)!=NULL)
       
   273 				{
       
   274 				qptr->SqueezeDown();
       
   275 				}
       
   276 			const TInt newSize = RequiredQueueSize(iNumConnections);
       
   277 			TRAP_IGNORE(AdjustQueueSizeL(newSize));
       
   278 			// Can easily leave as we need to allocate the new smaller queue before freeing
       
   279 			// the old queue. But if it does it doesn't matter as we'll simply be left with
       
   280 			// a larger than necessary buffer until the next realloc
       
   281 			}
       
   282 		iCount=0;
       
   283 		}
       
   284 	__CHECK_QUEUE();
       
   285 	Signal();
       
   286 	}
       
   287 
       
   288 void CEventQueue::IncreaseQueueSize(TInt aNumSpaces)
       
   289 	{
       
   290 	if ((iQueueSize+aNumSpaces)>EMaxQueueSize)
       
   291 		aNumSpaces=EMaxQueueSize-iQueueSize;
       
   292 	EventCopy(iEventPtr+iHead+aNumSpaces, iEventPtr+iHead, iQueueSize-iHead);
       
   293 	__ZAP_EVENTS(iEventPtr+iHead, aNumSpaces);
       
   294 	iQueueSize+=aNumSpaces;
       
   295 	iHead=(iHead+aNumSpaces)%iQueueSize;
       
   296 	}
       
   297 
       
   298 TBool CEventQueue::Expand(TWservEventPriorities aPriority)
       
   299 	{
       
   300 	if (iQueueSize==EMaxQueueSize)
       
   301 		{
       
   302 		if (aPriority==EEventPriorityHigh)
       
   303 			{
       
   304 			Purge();
       
   305 			if (iCount<iQueueSize)
       
   306 				return(ETrue);	// Success!
       
   307 			}
       
   308 		}
       
   309 	else if (doExpand(ECompressNoPurge) ||
       
   310 			  doExpand(ECompressPurge1) ||
       
   311 			   (aPriority==EEventPriorityHigh && doExpand(ECompressPurge2)))
       
   312 		return(ETrue);
       
   313 	return(EFalse);				// Failure
       
   314 	}
       
   315 
       
   316 TBool CEventQueue::doExpand(TCompressMode aCompressMode)
       
   317 	{
       
   318 	TDblQueIter<CEventQueue> iter(iQueueList);
       
   319 	iter.SetToLast();
       
   320 	CEventQueue* qptr=NULL;
       
   321 	TInt spare=0;
       
   322 	
       
   323 	// while loop from last queue till current queue, moving all queues up 
       
   324 	// to get all the space from between them
       
   325 	while((qptr=iter)!=this)
       
   326 		{
       
   327 		spare=qptr->SqueezeUp();
       
   328 		if (spare==0)
       
   329 			qptr->Compress(aCompressMode);
       
   330 		iter--;
       
   331 		}
       
   332 
       
   333 	// current queue, if we have space then expand the same and return
       
   334 	spare=FollowingGap();
       
   335 	if (spare>0)
       
   336 		{
       
   337 		IncreaseQueueSize(spare);
       
   338 		__CHECK_QUEUE();
       
   339 		return(ETrue);
       
   340 		}
       
   341 
       
   342 	// while loop from current queue till first queue, looking for a gap 
       
   343 	// between queues and using the first one it finds
       
   344 	iter--;
       
   345 	TInt expanded=0;
       
   346 	while((qptr=iter)!=NULL)
       
   347 		{
       
   348 		expanded=qptr->SqueezeUp();
       
   349 		if (expanded>0)
       
   350 			{
       
   351 			return MoveDownAndExpand(iter, expanded);
       
   352 			}
       
   353 		else
       
   354 			qptr->Compress(aCompressMode);
       
   355 		iter--;
       
   356 		}
       
   357 
       
   358 	// Even by doing all the above if we did not find space then check if first 
       
   359 	// queue has some space before it. If so then make use of it and movedown all the 
       
   360 	// queue till the current queue and then use the space for expansion
       
   361 	iter.SetToFirst();
       
   362 	qptr=iter;
       
   363 	if (qptr->iEventPtr>iGlobalEventQueue)
       
   364 		{
       
   365 		return MoveDownAndExpand(iter, qptr->iEventPtr-iGlobalEventQueue);
       
   366 		}
       
   367 
       
   368 	__CHECK_QUEUE();
       
   369 	return(EFalse);	// Failed to expand enough room
       
   370 	}
       
   371 
       
   372 // This function moves the queue down by given amount and repeats this until
       
   373 // the current queue and then expand the same
       
   374 TBool CEventQueue::MoveDownAndExpand(TDblQueIter<CEventQueue> &aIter, TInt aExpand)
       
   375 	{
       
   376 	CEventQueue* qptr=NULL;
       
   377 	FOREVER
       
   378 		{
       
   379 		qptr=aIter++;
       
   380 		qptr->MoveDown(aExpand);
       
   381 		if (qptr==this)
       
   382 			{
       
   383 			IncreaseQueueSize(aExpand);
       
   384 			__CHECK_QUEUE();
       
   385 			break;
       
   386 			}
       
   387 		}
       
   388 	return ETrue;
       
   389 	}
       
   390 
       
   391 void CEventQueue::MoveDown(TInt aMove)
       
   392 	{
       
   393 	if (!aMove)
       
   394 		{
       
   395 		return;
       
   396 		}
       
   397 	EventCopy(iEventPtr-aMove,iEventPtr,iQueueSize);
       
   398 	iEventPtr-=aMove;
       
   399 	}
       
   400 
       
   401 /*void CEventQueue::LogUpDownEvents(TChar aChar)
       
   402 	{
       
   403 	TWsEvent *event;
       
   404 	TBuf<128> buf;
       
   405 	buf.Zero();
       
   406 	buf.Append(aChar);
       
   407 	buf.Append('#');
       
   408 	buf.Append('#');
       
   409 	TBool some=EFalse;
       
   410 	TInt index;
       
   411 
       
   412 	for (index=0;index<iCount;index++)
       
   413 		{
       
   414 		event=EventPtr(index);
       
   415 		if (event->Type()==EEventPointer)
       
   416 			{
       
   417 			if (event->Pointer()->iType==TPointerEvent::EButton1Down
       
   418 										|| event->Pointer()->iType==TPointerEvent::EButton1Up)
       
   419 				{
       
   420 				some=ETrue;
       
   421 				if (event->Pointer()->iType==TPointerEvent::EButton1Down)
       
   422 					buf.Append('D');
       
   423 				else
       
   424 					buf.Append('U');
       
   425 				buf.AppendNum(index);
       
   426 				}
       
   427 			}
       
   428 		}
       
   429 	if (wsDebugLog)
       
   430 		wsDebugLog->MiscMessage(ELogImportant,buf);
       
   431 	}*/
       
   432 
       
   433 inline void CEventQueue::IncEventPointer(TWsEvent*& aEventPtr)
       
   434 	{
       
   435 	// iEventPtr[iQueueSize] is the element beyond the array, used for efficient bounds checking of the circular buffer only, do not access!!
       
   436 	if(++aEventPtr==&iEventPtr[iQueueSize])
       
   437 		{
       
   438 		aEventPtr=iEventPtr;
       
   439 		}
       
   440 	}
       
   441 
       
   442 inline void CEventQueue::DecEventPointer(TWsEvent*& aEventPtr)
       
   443 	{
       
   444 	if(aEventPtr--==iEventPtr)
       
   445 		{
       
   446 		aEventPtr=&iEventPtr[iQueueSize - 1];
       
   447 		}
       
   448 	}
       
   449 
       
   450 /*
       
   451 Starting from aEventToPurge searches the queue for matching event by iterating towards end of queue.
       
   452 Matching event will be a pointer event with the same window handle and pointer number
       
   453 as aEventToPurge, but will have type aMatchingType. If matching event is found, it will 
       
   454 be removed from the queue and search will finish.
       
   455 
       
   456 Search will be stopped if an event of type aSearchTerminator is found with the same pointer number 
       
   457 as aEventToPurge.
       
   458 
       
   459 If search is not stopped by aSearchTerminator and matching event is not found, TWsPointer
       
   460 class is notified that matching event has not been removed, so if it arrives in the future,
       
   461 TWsPointer class will be able to ignore it.
       
   462 */
       
   463 void CEventQueue::PurgeEventPairs(TWsEvent* aEventToPurge, TPointerEvent::TType aMatchingType, TPointerEvent::TType aSearchTerminator)
       
   464 		{
       
   465 		TWsEvent* eventToMatch = aEventToPurge;
       
   466 		TWsEvent* lastEvent = EventPtr(iCount);
       
   467 		for(IncEventPointer(eventToMatch);eventToMatch!=lastEvent;IncEventPointer(eventToMatch))
       
   468 			{
       
   469 			if ( (eventToMatch->Type()==EEventPointer)  // Must be checked first to ensure it is pointer data checked later
       
   470 					&&	(TAdvancedPointerEventHelper::PointerNumber(*eventToMatch) == TAdvancedPointerEventHelper::PointerNumber(*aEventToPurge))) // same pointer 
       
   471 				{
       
   472 				if ((eventToMatch->Pointer()->iType==aMatchingType) // correct event type
       
   473 						&& (eventToMatch->Handle()==aEventToPurge->Handle())) // same window
       
   474 					{
       
   475 					*eventToMatch=iNullEvent;
       
   476 					return;
       
   477 					}
       
   478 				else if (eventToMatch->Pointer()->iType==aSearchTerminator) // stop searching for mathing type
       
   479 					{
       
   480 					return;
       
   481 					}
       
   482 				}
       
   483 			};
       
   484 		TWsPointer::UnmatchedEventPurged(aMatchingType, aEventToPurge);
       
   485 		}
       
   486 
       
   487 /**
       
   488 Starting from pointer event aBasePointerEvent searches the queue for next pointer event for 
       
   489 the same pointer by iterating towards end of queue.
       
   490 
       
   491 @param aBasePointerEvent must be of type EEventPointer
       
   492 @return Next pointer event in the queue for the same pointer as aBasePointerEvent 
       
   493         if it has the same handle as aBasePointerEvent or NULL if it has different handle.
       
   494         NULL if there is no next pointer event for the same pointer in the queue.
       
   495 */
       
   496 TWsEvent* CEventQueue::NextPointerEvent(TWsEvent* aBasePointerEvent)
       
   497 	{
       
   498 	WS_ASSERT_DEBUG(aBasePointerEvent->Type() == EEventPointer, EWsPanicCheckEventQueue);
       
   499 	TWsEvent* currentEvent = aBasePointerEvent;
       
   500 	TWsEvent* lastEvent = EventPtr(iCount);
       
   501 	TUint8 pointerNumber = TAdvancedPointerEventHelper::PointerNumber(*aBasePointerEvent);
       
   502 	TUint handle = aBasePointerEvent->Handle();
       
   503 	for(IncEventPointer(currentEvent);currentEvent!=lastEvent;IncEventPointer(currentEvent))
       
   504 		{
       
   505 		if ((currentEvent->Type() == EEventPointer) && 
       
   506 			(TAdvancedPointerEventHelper::PointerNumber(*currentEvent) == pointerNumber))
       
   507 			{
       
   508 			if (currentEvent->Handle() == handle)
       
   509 				{
       
   510 				return currentEvent;
       
   511 				}
       
   512 			else
       
   513 				{
       
   514 				return NULL;
       
   515 				}
       
   516 			}
       
   517 		};
       
   518 	return NULL;
       
   519 	}
       
   520 	
       
   521 /**
       
   522 Checks if aEventToPurge should be purged. If it can be purged, then events that should
       
   523 be purged together with aEventToPurge (matching events) are overwritten with iNullEvent.
       
   524 
       
   525 @return ETrue if aEventToPurge should be purged, EFalse otherwise.
       
   526 */
       
   527 TBool CEventQueue::CheckPurgePointerEvent(TWsEvent* aEventToPurge)
       
   528 	{
       
   529 	switch(aEventToPurge->Pointer()->iType)
       
   530 		{
       
   531 		case TPointerEvent::EDrag:
       
   532 		case TPointerEvent::EMove:
       
   533 		case TPointerEvent::EButtonRepeat:
       
   534 		case TPointerEvent::ESwitchOn:
       
   535 			return ETrue;
       
   536 		case TPointerEvent::EButton1Down:
       
   537 			PurgeEventPairs(aEventToPurge,TPointerEvent::EButton1Up, TPointerEvent::ENullType);
       
   538 			return ETrue;
       
   539 		case TPointerEvent::EButton2Down:
       
   540 			PurgeEventPairs(aEventToPurge,TPointerEvent::EButton2Up, TPointerEvent::ENullType);
       
   541 			return ETrue;
       
   542 		case TPointerEvent::EButton3Down:
       
   543 			PurgeEventPairs(aEventToPurge,TPointerEvent::EButton3Up, TPointerEvent::ENullType);
       
   544 			return ETrue;
       
   545 		case TPointerEvent::EEnterHighPressure:
       
   546 			PurgeEventPairs(aEventToPurge,TPointerEvent::EExitHighPressure, TPointerEvent::EButton1Up);
       
   547 			return ETrue;
       
   548 		case TPointerEvent::EEnterCloseProximity:
       
   549 			{
       
   550 			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
       
   551 			if (nextEvent != NULL)
       
   552 				{
       
   553 				switch(nextEvent->Pointer()->iType)
       
   554 					{
       
   555 					case TPointerEvent::EExitCloseProximity: 
       
   556 						*nextEvent = iNullEvent;
       
   557 					case TPointerEvent::EOutOfRange:
       
   558 						return ETrue;
       
   559 					}
       
   560 				}
       
   561 			break;
       
   562 			}
       
   563 		case TPointerEvent::EExitCloseProximity:
       
   564 			{
       
   565 			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
       
   566 			if (nextEvent != NULL)
       
   567 				{
       
   568 				switch(nextEvent->Pointer()->iType)
       
   569 					{
       
   570 					case TPointerEvent::EEnterCloseProximity: 
       
   571 						*nextEvent = iNullEvent;
       
   572 					case TPointerEvent::EOutOfRange:
       
   573 						return ETrue;
       
   574 					}
       
   575 				}
       
   576 			break;
       
   577 			}
       
   578 		case TPointerEvent::EOutOfRange:
       
   579 			{
       
   580 			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
       
   581 			if ((nextEvent != NULL) &&
       
   582 				(nextEvent->Pointer()->iType == TPointerEvent::EOutOfRange))
       
   583 				{
       
   584 				return ETrue;
       
   585 				}
       
   586 			break;
       
   587 			}
       
   588 		case TPointerEvent::EExitHighPressure:
       
   589 			{
       
   590 			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
       
   591 			if ((nextEvent != NULL) &&
       
   592 				(nextEvent->Pointer()->iType == TPointerEvent::EButton1Up))
       
   593 				{
       
   594 				return ETrue;
       
   595 				}
       
   596 			break;
       
   597 			}
       
   598 		case TPointerEvent::EButton1Up:
       
   599 		case TPointerEvent::EButton2Up:
       
   600 		case TPointerEvent::EButton3Up:
       
   601 			break;
       
   602 		}
       
   603 	return EFalse;
       
   604 	}
       
   605 
       
   606 /** Purgable events are:
       
   607 	Pointer Up/Down pairs belonging to the same pointer, button and window
       
   608     Pointer moves & drags
       
   609     Key messages
       
   610     Key Up/Down pairs
       
   611     Key Ups if not foreground connection
       
   612     Focus lost/gained pairs
       
   613     EEnterHighPressure/EExitHighPressure pairs belonging to the same pointer
       
   614     EEnterCloseProximity/EExitCloseProximity pairs belonging to the same pointer
       
   615     Lone EEnterHighPressure, EExitHighPressure if followed by Up for the same pointer
       
   616     Lone EEnterCloseProximity, EExitCloseProximity if followed by EOutOfRange for the same pointer
       
   617     EOutOfRange if followed by another EOutOfRange for the same pointer
       
   618 
       
   619     Events that must not be purged:
       
   620     Key ups for foreground connections queue
       
   621     Lone pointer ups, must be delivered to match preceeding pointer down
       
   622     Lone EExitHighPressure if not followed by Up, must be delivered to match preceeding EEnterHighPressure
       
   623     Lone EEnterCloseProximity, EExitCloseProximity not followed by EOutOfRange for the same pointer
       
   624     Lone focus lost/gained messages
       
   625 */	
       
   626 void CEventQueue::Purge()
       
   627 	{
       
   628 	TWsEvent* eventToPurge;
       
   629 	TWsEvent* eventToMatch;
       
   630 	TInt indexToMatch;
       
   631 	TInt indexToPurge=iCount;
       
   632 	while(indexToPurge>0)
       
   633 		{
       
   634 		eventToPurge=EventPtr(--indexToPurge);
       
   635 		switch(eventToPurge->Type())
       
   636 			{
       
   637 			case EEventPassword:
       
   638 				break;
       
   639 			case EEventMarkInvalid:
       
   640 #if defined(_DEBUG)
       
   641 				WS_PANIC_DEBUG(EWsPanicCheckEventQueue);
       
   642 #endif
       
   643 			case EEventNull:
       
   644 			case EEventKey:
       
   645 			case EEventPointerEnter:
       
   646 			case EEventPointerExit:
       
   647 			case EEventDragDrop:
       
   648 breakLoopAndRemoveEvent:
       
   649 				RemoveEvent(indexToPurge);
       
   650 				return;
       
   651 			case EEventKeyUp:
       
   652 				if (iQueueList.First()!=this)
       
   653 					goto breakLoopAndRemoveEvent;
       
   654 				break;
       
   655 			case EEventKeyDown:
       
   656 				if (iQueueList.First()!=this)
       
   657 					goto breakLoopAndRemoveEvent;
       
   658 				for (indexToMatch=indexToPurge+1;indexToMatch<iCount;indexToMatch++)
       
   659 					{
       
   660 					eventToMatch=EventPtr(indexToMatch);
       
   661 					if (eventToMatch->Type()==EEventKeyUp && eventToMatch->Key()->iScanCode==eventToPurge->Key()->iScanCode)
       
   662 						{
       
   663 						*eventToMatch=iNullEvent;
       
   664 						goto breakLoopAndRemoveEvent;
       
   665 						}
       
   666 					}
       
   667 				break;
       
   668 			case EEventModifiersChanged:
       
   669 				for (indexToMatch=indexToPurge;indexToMatch>0;)
       
   670 					{
       
   671 					eventToMatch=EventPtr(--indexToMatch);
       
   672 					if (eventToMatch->Type()==EEventModifiersChanged)
       
   673 						{
       
   674 						eventToPurge->ModifiersChanged()->iChangedModifiers|=eventToMatch->ModifiersChanged()->iChangedModifiers;
       
   675 						indexToPurge=indexToMatch;
       
   676 						goto breakLoopAndRemoveEvent;
       
   677 						}
       
   678 					}
       
   679 				break;
       
   680 			case EEventPointerBufferReady:
       
   681 				CWsPointerBuffer::DiscardPointerMoveBuffer(eventToPurge->Handle());
       
   682 				goto breakLoopAndRemoveEvent;
       
   683 			case EEventFocusLost:
       
   684 			case EEventFocusGained:
       
   685 				if ((indexToPurge+1)<iCount)
       
   686 					{
       
   687 					eventToMatch=EventPtr(indexToPurge+1);
       
   688 					if (eventToMatch->Type()==EEventFocusLost || eventToMatch->Type()==EEventFocusGained)
       
   689 						{
       
   690 						*eventToMatch=iNullEvent;
       
   691 						goto breakLoopAndRemoveEvent;
       
   692 						}
       
   693 					}
       
   694 				break;
       
   695 			case EEventSwitchOn:
       
   696 				if ((indexToPurge+1)<iCount && EventPtr(indexToPurge+1)->Type()==EEventSwitchOn)
       
   697 					goto breakLoopAndRemoveEvent;
       
   698 				break;
       
   699 			case EEventPointer:
       
   700 				if (CheckPurgePointerEvent(eventToPurge))
       
   701 					{
       
   702 					goto breakLoopAndRemoveEvent;
       
   703 					}
       
   704 				break;
       
   705 			}
       
   706 		}
       
   707 	}
       
   708 
       
   709 void CEventQueue::PurgePointerEvents()
       
   710 	{
       
   711 	TWsEvent* eventToPurge;
       
   712 	TInt indexToPurge=iCount;
       
   713 	while(indexToPurge>0)
       
   714 		{
       
   715 		eventToPurge=EventPtr(--indexToPurge);
       
   716 		switch(eventToPurge->Type())
       
   717 			{
       
   718 			case EEventPointerBufferReady:
       
   719 				CWsPointerBuffer::DiscardPointerMoveBuffer(eventToPurge->Handle());
       
   720 				RemoveEvent(indexToPurge);
       
   721 				break;
       
   722 			case EEventPointer:
       
   723 				if (CheckPurgePointerEvent(eventToPurge))
       
   724 					{
       
   725 					RemoveEvent(indexToPurge);
       
   726 					}
       
   727 				break;
       
   728 			}
       
   729 		}
       
   730 	}
       
   731 
       
   732 /**
       
   733 Purge requested number of oldest events from inactive event queue.
       
   734 @param aSizeRequired the total events required to be cleared. 
       
   735 @return The number of events cleared.
       
   736 */
       
   737 TInt CEventQueue::PurgeInactiveEvents(const TInt& aSizeRequired)
       
   738 	{
       
   739 	TInt numEventsCleared = 0;
       
   740 	CEventQueue* qptr;
       
   741 	TBool isRemoved;
       
   742 	do	{
       
   743 		TDblQueIter<CEventQueue> iter(iQueueList);
       
   744 		isRemoved = EFalse;
       
   745 		while ((qptr = iter++) != NULL && (aSizeRequired > numEventsCleared))
       
   746 			{
       
   747 			if ((qptr->IsEventCancelled() || (qptr->iEventMsg.IsNull() && !qptr->iEventSignalledState)) &&
       
   748 				(qptr->iQueueSize > EMinQueueSize))
       
   749 				{
       
   750 				// we have a client that is not listening with a size larger than min queue size.
       
   751 				// so lets remove it's oldest event until the number of removed events meet the requirement.
       
   752 				qptr->RemoveEvent(0);
       
   753 				numEventsCleared++;
       
   754 				isRemoved = ETrue;
       
   755 				}
       
   756 			}
       
   757 		} while ((aSizeRequired > numEventsCleared) && isRemoved);
       
   758 	return numEventsCleared;
       
   759 	}
       
   760 
       
   761 void CEventQueue::Compress(TCompressMode aCompressMode)
       
   762 	{
       
   763 //
       
   764 // The different purge modes are
       
   765 //
       
   766 // ECompressNoPurge,	// Don't purge anything
       
   767 // ECompressPurge1,		// Don't purge foreground queue
       
   768 // ECompressPurge2,		// Purge all queues
       
   769 //
       
   770 	if (aCompressMode==ECompressPurge2 ||
       
   771 		(this!=iQueueList.First() && aCompressMode==ECompressPurge1))
       
   772 		Purge();
       
   773 	TInt compress=iQueueSize-(iCount>EMinQueueSize?iCount:EMinQueueSize);
       
   774 	if (compress>0)
       
   775 		{
       
   776 		compress=(compress+1)/2;	// Compress half the free space in the queue
       
   777 		TWsEvent* head=EventPtr(0);
       
   778 		TWsEvent* tail=EventPtr(iCount);
       
   779 		if (head>tail)
       
   780 			{
       
   781 			EventCopy(iEventPtr+compress,iEventPtr,tail-iEventPtr);
       
   782 			iHead-=compress;
       
   783 			}
       
   784 		else
       
   785 			{
       
   786 			EventCopy(iEventPtr+compress,head,iCount);
       
   787 			iHead=0;
       
   788 			}
       
   789 		iEventPtr+=compress;
       
   790 		iQueueSize-=compress;
       
   791 		}
       
   792 	}
       
   793 
       
   794 void CEventQueue::MoveUp(TInt aNumEvents)
       
   795 	{
       
   796 	if (!aNumEvents)
       
   797 		{
       
   798 		return;
       
   799 		}
       
   800 	EventCopy(iEventPtr+aNumEvents,iEventPtr,iQueueSize);
       
   801 	iEventPtr+=aNumEvents;
       
   802 	}
       
   803 
       
   804 TInt CEventQueue::FollowingGap() const
       
   805 	{
       
   806 	TDblQueIter<CEventQueue> iter(iQueueList);
       
   807 	CEventQueue* qptr;
       
   808 	iter.Set(*(CEventQueue *)this);
       
   809 	iter++;
       
   810 	TWsEvent* end;
       
   811 	if ((qptr=iter)!=NULL)
       
   812 		end=qptr->iEventPtr;
       
   813 	else
       
   814 		end=iGlobalEventQueue+iGlobalEventQueueSize;
       
   815 	return(end-(iEventPtr+iQueueSize));
       
   816 	}
       
   817 
       
   818 TInt CEventQueue::SqueezeUp()
       
   819 	{
       
   820 	TInt gap=FollowingGap();
       
   821 	MoveUp(gap);
       
   822 	return(gap);
       
   823 	}
       
   824 
       
   825 void CEventQueue::SqueezeDown()
       
   826 	{
       
   827 	TDblQueIter<CEventQueue> iter(iQueueList);
       
   828 	iter.Set(*this);
       
   829 	iter--;
       
   830 	CEventQueue* qptr=iter;
       
   831 	if (qptr!=NULL)
       
   832 		{
       
   833 		Compress(ECompressNoPurge);
       
   834 		TInt gap=qptr->FollowingGap();
       
   835 		MoveDown(gap);
       
   836 		}
       
   837 	}
       
   838 
       
   839 void CEventQueue::MoveToFront()
       
   840 	{
       
   841 	if (this==iQueueList.First())
       
   842 		return;
       
   843 	Wait();
       
   844 	CEventQueue* qptr;
       
   845 	TInt gap=0;
       
   846 	TDblQueIter<CEventQueue> iter(iQueueList);
       
   847 	iter.SetToLast();
       
   848 	while((qptr=iter--)!=NULL)
       
   849 		{
       
   850 		if (gap<iQueueSize)
       
   851 			qptr->Compress(ECompressNoPurge);
       
   852 		gap=qptr->SqueezeUp();
       
   853 		}
       
   854 	if (gap>=iQueueSize)
       
   855 		EventCopy(iGlobalEventQueue,iEventPtr,iQueueSize);
       
   856 	else
       
   857 		{
       
   858 		EventCopy(iGlobalEventQueue,iEventPtr,gap);
       
   859 		iEventPtr+=gap;
       
   860 		TWsEvent copyBuf[ECopyBufSize];	// temp buffer, can copy upto ECopyBufSize events at a time
       
   861 		TInt eventsToGo=iQueueSize-gap;
       
   862 		iQueueSize=gap;
       
   863 		do
       
   864 			{
       
   865 			TInt copy=Min(eventsToGo,ECopyBufSize);
       
   866 			Mem::Copy(&copyBuf[0],iEventPtr,copy*sizeof(TWsEvent));
       
   867 			iter.Set(*this);
       
   868 			iter--;
       
   869 			while((qptr=iter--)!=NULL)
       
   870 				qptr->MoveUp(copy);
       
   871 			EventCopy(iGlobalEventQueue+iQueueSize,&copyBuf[0],copy);
       
   872 			iQueueSize+=copy;
       
   873 			eventsToGo-=copy;
       
   874 			iEventPtr+=copy;
       
   875 			} while(eventsToGo>0);
       
   876 		}
       
   877 	iEventPtr=iGlobalEventQueue;
       
   878 	this->iLink.Deque();
       
   879 	iQueueList.AddFirst(*this);
       
   880 	__CHECK_QUEUE();
       
   881 	Signal();
       
   882 	}
       
   883 
       
   884 // CEventQueue
       
   885 
       
   886 CEventQueue::CEventQueue(CWsClient* aOwner) : CEventBase(aOwner)
       
   887 	{
       
   888 	__DECLARE_NAME(_S("CEventQueue"));
       
   889 	}
       
   890 
       
   891 CEventQueue::~CEventQueue()
       
   892 	{
       
   893 	RemoveQueue();
       
   894 	}
       
   895 
       
   896 void CEventQueue::InitStaticsL()
       
   897 	{
       
   898 	User::LeaveIfError(iMutex.CreateLocal());
       
   899 	}
       
   900 
       
   901 void CEventQueue::DeleteStaticsL()
       
   902 	{
       
   903 	iMutex.Close();
       
   904 	}
       
   905 
       
   906 void CEventQueue::ConstructL()
       
   907 	{
       
   908 	AddQueueL();
       
   909 	Mem::FillZ(&iNullEvent,sizeof(iNullEvent));
       
   910 	}
       
   911 
       
   912 TWsEvent* CEventQueue::EventPtr(TInt index)	
       
   913 	{
       
   914 	return(iEventPtr+((iHead+index)%iQueueSize));
       
   915 	}
       
   916 
       
   917 TBool CEventQueue::QueueEvent(const TWsEvent &event)
       
   918 	{
       
   919 	TWservEventPriorities priority=EEventPriorityLow;
       
   920 #ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP
       
   921 	if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || 
       
   922 		event.Type()==EEventKeySwitchOff || event.Type()==EEventRestartSystem)
       
   923 #else
       
   924 	if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || event.Type()==EEventKeySwitchOff)
       
   925 #endif
       
   926 		{
       
   927 		priority=EEventPriorityHigh;
       
   928 		}
       
   929 	return(QueueEvent(event,priority));
       
   930 	}
       
   931 
       
   932 TBool CEventQueue::CheckRoom()
       
   933 //
       
   934 // If the queue is full and room is created return ETrue
       
   935 //
       
   936 	{
       
   937 	TBool ret=EFalse;
       
   938 	Wait();
       
   939 	if (iCount==iQueueSize && Expand(EEventPriorityHigh))
       
   940 		ret=ETrue;
       
   941 	Signal();
       
   942 	return(ret);
       
   943 	}
       
   944 
       
   945 TBool CEventQueue::QueueEvent(const TWsEvent &event, TWservEventPriorities aPriority)
       
   946 //
       
   947 // Queue an event, returns ETrue if queued or delivered, EFalse if the queue was full.
       
   948 //
       
   949 	{
       
   950 	TBool ret=ETrue;
       
   951 	Wait();
       
   952 	if (iCount==iQueueSize && !Expand(aPriority))
       
   953 		ret=EFalse;
       
   954 	else
       
   955 		{
       
   956 		if (!iEventMsg.IsNull())
       
   957 			{
       
   958 			SignalEvent();
       
   959 			}
       
   960 		*EventPtr(iCount++)=event;
       
   961 		}
       
   962 	Signal();
       
   963 	return(ret);
       
   964 	}
       
   965 
       
   966 TBool CEventQueue::QueueEvent(TUint32 aTarget, TInt aEvent, TInt aIntVal)
       
   967 	{
       
   968 	TWsEvent event;
       
   969 	event.SetType(aEvent);
       
   970 	event.SetHandle(aTarget);
       
   971 	event.SetTimeNow();
       
   972 	*(event.Int()) = aIntVal;
       
   973 	return(QueueEvent(event));
       
   974 	}
       
   975 
       
   976 void CEventQueue::UpdateLastEvent(const TWsEvent &event)
       
   977 	{
       
   978 	WS_ASSERT_DEBUG(iCount>0, EWsPanicQueueUpdateCount);
       
   979 	Mem::Copy(EventPtr(iCount-1)->EventData(),event.EventData(),TWsEvent::EWsEventDataSize);
       
   980 	}
       
   981 
       
   982 /*
       
   983 Replaces last pointer event related to particular pointer with new one.
       
   984 
       
   985 While searching for event to replace this method considers all events on the
       
   986 queue except EMove and EDrag pointer events from pointers different than aEvent. 
       
   987 If the last of these events under consideration:
       
   988 (1) is a pointer event, 
       
   989 (2) has the same type as aEvent,
       
   990 (3) its type is either EMove or EDrag and
       
   991 (4) has the same window handle as aEvent,
       
   992 then it is removed from the queue and aEvent is put at the end of the queue.
       
   993 
       
   994 @return ETrue if event on the queue has been replaced with aEvent, EFalse otherwise. 
       
   995 */
       
   996 TBool CEventQueue::UpdateLastPointerEvent(const TWsEvent &aEvent)
       
   997 	{
       
   998 	if (aEvent.Pointer()->iType == TPointerEvent::EMove || aEvent.Pointer()->iType == TPointerEvent::EDrag)
       
   999 		{
       
  1000 		Wait();
       
  1001 		
       
  1002 		if (iCount == 0)
       
  1003 			{
       
  1004 			Signal();
       
  1005 			return EFalse;
       
  1006 			}
       
  1007 		
       
  1008 		// loop through all events on the queue starting from the last one
       
  1009 		TWsEvent* evToUpdate = EventPtr(iCount);
       
  1010 		TWsEvent* evOnHead   = &iEventPtr[iHead]; 
       
  1011 		while (evToUpdate != evOnHead)
       
  1012 			{
       
  1013 			DecEventPointer(evToUpdate);
       
  1014 			
       
  1015 			// conditions that stop searching
       
  1016 			if (   (evToUpdate->Type() != EEventPointer)	// found non-pointer event
       
  1017 				|| (evToUpdate->Pointer()->iType != TPointerEvent::EMove && evToUpdate->Pointer()->iType != TPointerEvent::EDrag)	// pointer event but wrong type
       
  1018 				|| (   (TAdvancedPointerEventHelper::PointerNumber(*evToUpdate) == TAdvancedPointerEventHelper::PointerNumber(aEvent))
       
  1019 				    && (   (evToUpdate->Handle() != aEvent.Handle())					// good number & bad handle         
       
  1020 				        || (evToUpdate->Pointer()->iType != aEvent.Pointer()->iType)))) // good number & bad type
       
  1021 				{
       
  1022 				Signal();
       
  1023 				return EFalse;
       
  1024 				}
       
  1025 			else if (TAdvancedPointerEventHelper::PointerNumber(*evToUpdate) == TAdvancedPointerEventHelper::PointerNumber(aEvent))
       
  1026 				{
       
  1027 				// we found event to update: evToUpdate is pointer event with right type, pointer number
       
  1028 				// and window handle
       
  1029 				
       
  1030 				if (evToUpdate == EventPtr(iCount - 1))
       
  1031 					{
       
  1032 					UpdateLastEvent(aEvent);
       
  1033 					}
       
  1034 				else
       
  1035 					{
       
  1036 					RemoveEvent(evToUpdate);
       
  1037 					*EventPtr(iCount++) = aEvent;
       
  1038 					}
       
  1039 				Signal();
       
  1040 				return ETrue;
       
  1041 				}
       
  1042 			
       
  1043 			// evToUpdate is EMove or EDrag pointer event with different pointer id,
       
  1044 			// continue to loop through the queue
       
  1045 			}
       
  1046 		Signal();
       
  1047 		}
       
  1048 	return EFalse;
       
  1049 	}
       
  1050 
       
  1051 void CEventQueue::GetData()
       
  1052 //
       
  1053 // If there is an outstanding event in the queue, reply with it's data and remove it from the Q
       
  1054 //
       
  1055 	{
       
  1056 	if (iCount>0)
       
  1057 		{
       
  1058 		WS_ASSERT_DEBUG((iEventPtr+iHead)->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
       
  1059 		CEventBase::GetData(iEventPtr+iHead,sizeof(*iEventPtr));
       
  1060 		__ZAP_EVENT(iEventPtr+iHead);
       
  1061 		iHead=(iHead+1)%iQueueSize;
       
  1062 		iCount--;
       
  1063 		}
       
  1064 	else
       
  1065 		CEventBase::GetData(&iNullEvent,sizeof(iNullEvent));
       
  1066 	}
       
  1067 
       
  1068 void CEventQueue::EventReady(const RMessagePtr2& aEventMsg)
       
  1069 //
       
  1070 // Queue a read of an event notification
       
  1071 //
       
  1072 	{
       
  1073 	EventReadyCheck();
       
  1074 	Wait();
       
  1075 	iEventMsg=aEventMsg;
       
  1076 	if (iCount>0)
       
  1077 		SignalEvent();
       
  1078 	Signal();
       
  1079 	}
       
  1080 
       
  1081 void CEventQueue::RemoveEvent(TInt index)
       
  1082 //
       
  1083 // Remove event 'index' in the queue, this event MUST exist in the queue
       
  1084 //
       
  1085 	{
       
  1086 	WS_ASSERT_DEBUG(index < iCount, EWsPanicCheckEventQueue);
       
  1087 	RemoveEvent(EventPtr(index));
       
  1088 	}
       
  1089 
       
  1090 void CEventQueue::RemoveEvent(TWsEvent* aEvToRemove)
       
  1091 //
       
  1092 // Remove event in the queue, this event MUST exist in the queue
       
  1093 //
       
  1094 	{
       
  1095 	iCount--;
       
  1096 	TWsEvent* last = EventPtr(iCount);
       
  1097 	TWsEvent* prev;
       
  1098 	while(aEvToRemove!=last)
       
  1099 		{
       
  1100 		prev = aEvToRemove;
       
  1101 		IncEventPointer(aEvToRemove);
       
  1102 		*prev = *aEvToRemove;
       
  1103 		}
       
  1104 	__ZAP_EVENT(last);
       
  1105 	}
       
  1106 
       
  1107 const TWsEvent* CEventQueue::PeekLastEvent()
       
  1108 //
       
  1109 // Return a read only pointer to the last event in the queue (or NULL if no event)
       
  1110 //
       
  1111 	{
       
  1112 	if (iCount==0)
       
  1113 		return(NULL);
       
  1114 	return(EventPtr(iCount-1));
       
  1115 	}
       
  1116 
       
  1117 void CEventQueue::Wait()
       
  1118 	{
       
  1119 	iMutex.Wait();
       
  1120 	}
       
  1121 
       
  1122 void CEventQueue::Signal()
       
  1123 	{
       
  1124 	iMutex.Signal();
       
  1125 	}
       
  1126 
       
  1127 void CEventQueue::WalkEventQueue(EventQueueWalk aFunc, TAny* aFuncParam)
       
  1128 	{
       
  1129 	Wait();
       
  1130 restart:
       
  1131 	for (TInt index=0;index<iCount;index++)
       
  1132 		{
       
  1133 		TWsEvent* event=EventPtr(index);
       
  1134 		switch((aFunc)(aFuncParam,event))
       
  1135 			{
       
  1136 			case EEventQueueWalkDeleteEvent:
       
  1137 				RemoveEvent(index--);
       
  1138 			case EEventQueueWalkOk:
       
  1139 				break;
       
  1140 			case EEventQueueWalkRestart:
       
  1141 				goto restart;
       
  1142 			}
       
  1143 		}
       
  1144 	Signal();
       
  1145 	}