os/graphics/windowing/windowserver/nga/SERVER/EVQUEUE.CPP
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/graphics/windowing/windowserver/nga/SERVER/EVQUEUE.CPP	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1173 @@
     1.4 +// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// Window server event queue handling
    1.18 +// 
    1.19 +//
    1.20 +
    1.21 +#include "EVQUEUE.H"
    1.22 +
    1.23 +#include "server.h"
    1.24 +#include "wstop.h"
    1.25 +#include "panics.h"
    1.26 +#include "pointer.h"
    1.27 +#include "advancedpointereventhelper.h"
    1.28 +#include "debughelper.h"
    1.29 +
    1.30 +GLREF_D CDebugLogBase* wsDebugLog;
    1.31 +
    1.32 +#if defined(_DEBUG)
    1.33 +#define __CHECK_QUEUE() CheckQueue()
    1.34 +#define __ZAP_EVENTS(pointer,len) ZapEvents(pointer,len)
    1.35 +#define __ZAP_EVENT(pointer) ZapEvent(pointer)
    1.36 +#else
    1.37 +#define __CHECK_QUEUE()
    1.38 +#define __ZAP_EVENTS(pointer,len)
    1.39 +#define __ZAP_EVENT(pointer)
    1.40 +#endif
    1.41 +
    1.42 +const TInt ECopyBufSize=4;
    1.43 +
    1.44 +TDblQue<CEventQueue> CEventQueue::iQueueList(_FOFF(CEventQueue,iLink));
    1.45 +TWsEvent* CEventQueue::iGlobalEventQueue=NULL;
    1.46 +TInt CEventQueue::iGlobalEventQueueSize=0;
    1.47 +TInt CEventQueue::iNumConnections=0;
    1.48 +RMutex CEventQueue::iMutex;
    1.49 +TWsEvent CEventQueue::iNullEvent;
    1.50 +
    1.51 +// CEventBase
    1.52 +
    1.53 +CEventBase::~CEventBase()
    1.54 +	{
    1.55 +	if (!iEventMsg.IsNull() && CWsTop::ShuttingDown())
    1.56 +		{
    1.57 +		iEventMsg.Complete(KErrServerTerminated);
    1.58 +		}
    1.59 +	}
    1.60 +
    1.61 +CEventBase::CEventBase(CWsClient* aOwner) : iWsOwner(aOwner)
    1.62 +	{
    1.63 +	}
    1.64 +
    1.65 +void CEventBase::SignalEvent(TInt aCode)
    1.66 +	{
    1.67 +	if (wsDebugLog)
    1.68 +		wsDebugLog->SignalEvent(iWsOwner->ConnectionHandle());
    1.69 +	iEventMsg.Complete(aCode);
    1.70 +	iEventSignalledState|=EEventFlagSignalled;
    1.71 +	}
    1.72 +
    1.73 +inline TBool CEventBase::IsEventCancelled()
    1.74 +	{
    1.75 +	return (iEventSignalledState & EEventFlagCancelled);
    1.76 +	}
    1.77 +
    1.78 +/**
    1.79 +If there is an outstanding read cancel it.
    1.80 +*/
    1.81 +void CEventBase::CancelRead()
    1.82 +	{
    1.83 +	if (!iEventMsg.IsNull())
    1.84 +		{
    1.85 +		iEventMsg.Complete(KErrCancel);
    1.86 +		}
    1.87 +	iEventSignalledState|=EEventFlagCancelled;
    1.88 +	}
    1.89 +
    1.90 +void CEventBase::GetData(TAny* aData, TInt aLen)
    1.91 +	{
    1.92 +	if (!(iEventSignalledState&EEventFlagSignalled))
    1.93 +		{
    1.94 +		iWsOwner->PPanic(EWservPanicUnsignalledEventData);
    1.95 +		}
    1.96 +	iEventSignalledState&=~EEventFlagSignalled;
    1.97 +	CWsClient::ReplyBuf(aData,aLen);
    1.98 +	}
    1.99 +
   1.100 +/**
   1.101 +Queue a read of an event notification
   1.102 +*/
   1.103 +void CEventBase::EventReadyCheck()
   1.104 +	{
   1.105 +	if ((iEventSignalledState&EEventFlagSignalled && !(iEventSignalledState&EEventFlagCancelled)) || !iEventMsg.IsNull())
   1.106 +		{
   1.107 +#ifdef LOG_WSERV_EVENTS
   1.108 +		RDebug::Printf("_WSEVENT: CEventBase::EventReadyCheck, Event is not ready");
   1.109 +#endif
   1.110 +		iWsOwner->PPanic(EWservPanicReadOutstanding);
   1.111 +		}
   1.112 +	}
   1.113 +
   1.114 +void CEventBase::EventReady(const RMessagePtr2& aEventMsg)
   1.115 +	{
   1.116 +	EventReadyCheck();
   1.117 +	iEventMsg=aEventMsg;
   1.118 +	}
   1.119 +
   1.120 +// CEventQueue - Queue organisation functions
   1.121 +
   1.122 +#if defined(_DEBUG)
   1.123 +void CEventQueue::CheckQueue()
   1.124 +	{
   1.125 +	TDblQueIter<CEventQueue> iter(iQueueList);
   1.126 +	CEventQueue* qptr;
   1.127 +	iter.SetToFirst();
   1.128 +	while((qptr=iter++)!=NULL)
   1.129 +		{
   1.130 +		WS_ASSERT_DEBUG(qptr->iQueueSize>=0 && qptr->iQueueSize<=iGlobalEventQueueSize, EWsPanicCheckEventQueue);
   1.131 +		WS_ASSERT_DEBUG(qptr->iQueueSize==0 || qptr->iHead<qptr->iQueueSize, EWsPanicCheckEventQueue);
   1.132 +		WS_ASSERT_DEBUG(qptr->iCount<=qptr->iQueueSize, EWsPanicCheckEventQueue);
   1.133 +		WS_ASSERT_DEBUG(qptr->iEventPtr>=iGlobalEventQueue && qptr->iEventPtr<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicCheckEventQueue);
   1.134 +		}
   1.135 +	for(TInt index=0;index<iCount;index++)
   1.136 +		{
   1.137 +		TWsEvent* ev=EventPtr(index);
   1.138 +		WS_ASSERT_DEBUG(ev->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
   1.139 +		}
   1.140 +	}
   1.141 +
   1.142 +void CEventQueue::ZapEvent(TWsEvent* aTarget)
   1.143 +	{
   1.144 +	aTarget->SetType(EEventMarkInvalid);
   1.145 +	aTarget->SetHandle(555);
   1.146 +	}
   1.147 +
   1.148 +void CEventQueue::ZapEvents(TWsEvent* aTarget, TInt aLen)
   1.149 +	{
   1.150 +	for(TInt index=0;index<aLen;index++)
   1.151 +		ZapEvent(aTarget+index);
   1.152 +	}
   1.153 +
   1.154 +#endif
   1.155 +
   1.156 +void CEventQueue::EventCopy(TWsEvent* aTarget, TWsEvent* aSource, TInt aNumEvents)
   1.157 +	{
   1.158 +	WS_ASSERT_DEBUG(aTarget>=iGlobalEventQueue, EWsPanicEventQueueCopy);
   1.159 +	WS_ASSERT_DEBUG((aTarget+aNumEvents)<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicEventQueueCopy);
   1.160 +	Mem::Copy(aTarget,aSource,aNumEvents*sizeof(TWsEvent));
   1.161 +	}
   1.162 +
   1.163 +TInt CEventQueue::RequiredQueueSize(TInt aNumConnections)
   1.164 +	{
   1.165 +	return(aNumConnections*EMinQueueSize+EMaxQueueSize+EExtraQueueSize);
   1.166 +	}
   1.167 +
   1.168 +/**
   1.169 +Adjust the Global Queue Size.
   1.170 +@param aNewSize the size for event queue. 
   1.171 +*/
   1.172 +void CEventQueue::AdjustQueueSizeL(TInt aNewSize)
   1.173 +	{
   1.174 +	TWsEvent* oldQ=iGlobalEventQueue;
   1.175 +	if (aNewSize < iGlobalEventQueueSize)
   1.176 +		{
   1.177 +		// Re-alloc wont move the cell down to a lower address, this means once this cell is
   1.178 +		// high up in memory it may never move down again, thus wasting loads of global heap space.
   1.179 +		const CEventQueue* last=iQueueList.Last();
   1.180 +		if ((last->iEventPtr + last->iQueueSize) >= (iGlobalEventQueue + aNewSize))
   1.181 +			{
   1.182 +			return;
   1.183 +			}
   1.184 +		TInt allocSize = aNewSize * sizeof(TWsEvent);
   1.185 +		iGlobalEventQueue=static_cast<TWsEvent*>(User::AllocL(allocSize));
   1.186 +		Mem::Copy(iGlobalEventQueue,oldQ,allocSize);
   1.187 +		User::Free(oldQ);
   1.188 +		}
   1.189 +	else
   1.190 +		{
   1.191 +		iGlobalEventQueue = static_cast<TWsEvent*>(User::ReAllocL(iGlobalEventQueue, aNewSize * sizeof(TWsEvent)));
   1.192 +		}
   1.193 +	__ZAP_EVENTS(iGlobalEventQueue + iGlobalEventQueueSize, aNewSize - iGlobalEventQueueSize); 
   1.194 +	iGlobalEventQueueSize = aNewSize; 
   1.195 +	// coverity[use_after_free]
   1.196 +	TInt diff=(reinterpret_cast<TInt8*>(iGlobalEventQueue)-reinterpret_cast<TInt8*>(oldQ));
   1.197 +	if (diff)
   1.198 +		{
   1.199 +		TDblQueIter<CEventQueue> iter(iQueueList);
   1.200 +		CEventQueue* qptr;
   1.201 +		while((qptr=iter++)!=NULL)
   1.202 +			{
   1.203 +			qptr->iEventPtr=reinterpret_cast<TWsEvent*>(reinterpret_cast<TInt8*>(qptr->iEventPtr)+diff);
   1.204 +			}
   1.205 +		}
   1.206 +	}
   1.207 +
   1.208 +void CEventQueue::AddQueueL()
   1.209 +	{
   1.210 +	Wait();
   1.211 +	if ((iNumConnections%EQueueGranularity)==0)
   1.212 +		{
   1.213 +		const TInt newSize = RequiredQueueSize(iNumConnections + EQueueGranularity);
   1.214 +		TRAPD(err,AdjustQueueSizeL(newSize));
   1.215 +		if (err!=KErrNone)
   1.216 +			{
   1.217 +			__CHECK_QUEUE();
   1.218 +			Signal();
   1.219 +			User::Leave(err);
   1.220 +			}
   1.221 +		}
   1.222 +	iNumConnections++;
   1.223 +	if (iQueueList.IsEmpty())
   1.224 +		iEventPtr=iGlobalEventQueue;
   1.225 +	else
   1.226 +		{
   1.227 +		CEventQueue* qptr=iQueueList.Last();
   1.228 +		iEventPtr=qptr->iEventPtr+qptr->iQueueSize;
   1.229 +		}
   1.230 +	iQueueList.AddLast(*this);
   1.231 +	
   1.232 +	//Initialize the queue size to at least EMinQueueSize
   1.233 +	//Check the queue by doing standard queue compression.
   1.234 +	TBool isExpanded = ETrue;
   1.235 +	do {isExpanded = Expand(EEventPriorityLow);} while ((iQueueSize < EMinQueueSize) && isExpanded);
   1.236 +	while (iQueueSize < EMinQueueSize)
   1.237 +		{
   1.238 +		//Cannot get enough spaces by doing standard queue compression,
   1.239 +		//try to grow the global queue.
   1.240 +		TInt sizeRequired = EMinQueueSize - iQueueSize;
   1.241 +		const TInt newSize = iGlobalEventQueueSize + sizeRequired;
   1.242 +		TRAPD(err, AdjustQueueSizeL(newSize));
   1.243 +		if (err != KErrNone)
   1.244 +			{
   1.245 +			//Cannot get enough spaces by growing global queue.
   1.246 +			//try to purge the oldest events from inactive clients.				
   1.247 +			TInt numEventCleared = PurgeInactiveEvents(sizeRequired);
   1.248 +			if (numEventCleared == 0)
   1.249 +				{
   1.250 +				__CHECK_QUEUE();
   1.251 +				Signal();
   1.252 +				User::Leave(err);
   1.253 +				}
   1.254 +			}
   1.255 +		while (doExpand(ECompressNoPurge)) {};
   1.256 +		}
   1.257 +	__CHECK_QUEUE();
   1.258 +	Signal();
   1.259 +	}
   1.260 +
   1.261 +void CEventQueue::RemoveQueue()
   1.262 +	{
   1.263 +	Wait();
   1.264 +	if (iEventPtr)	// If this is still NULL this class hasn't been linked into the Q list
   1.265 +		{
   1.266 +		__ZAP_EVENTS(iEventPtr, iQueueSize);
   1.267 +		iLink.Deque();
   1.268 +		if (--iNumConnections==0)
   1.269 +			{
   1.270 +			User::Free(iGlobalEventQueue);
   1.271 +			iGlobalEventQueue=NULL;
   1.272 +			iGlobalEventQueueSize=0;
   1.273 +			}
   1.274 +		else if ((iNumConnections%EQueueGranularity)==0)
   1.275 +			{
   1.276 +			TDblQueIter<CEventQueue> iter(iQueueList);
   1.277 +			CEventQueue* qptr=iter++;
   1.278 +			qptr->Compress(ECompressNoPurge);
   1.279 +			while((qptr=iter++)!=NULL)
   1.280 +				{
   1.281 +				qptr->SqueezeDown();
   1.282 +				}
   1.283 +			const TInt newSize = RequiredQueueSize(iNumConnections);
   1.284 +			TRAP_IGNORE(AdjustQueueSizeL(newSize));
   1.285 +			// Can easily leave as we need to allocate the new smaller queue before freeing
   1.286 +			// the old queue. But if it does it doesn't matter as we'll simply be left with
   1.287 +			// a larger than necessary buffer until the next realloc
   1.288 +			}
   1.289 +		iCount=0;
   1.290 +		}
   1.291 +	__CHECK_QUEUE();
   1.292 +	Signal();
   1.293 +	}
   1.294 +
   1.295 +void CEventQueue::IncreaseQueueSize(TInt aNumSpaces)
   1.296 +	{
   1.297 +	if ((iQueueSize+aNumSpaces)>EMaxQueueSize)
   1.298 +		aNumSpaces=EMaxQueueSize-iQueueSize;
   1.299 +	EventCopy(iEventPtr+iHead+aNumSpaces, iEventPtr+iHead, iQueueSize-iHead);
   1.300 +	__ZAP_EVENTS(iEventPtr+iHead, aNumSpaces);
   1.301 +	iQueueSize+=aNumSpaces;
   1.302 +	iHead=(iHead+aNumSpaces)%iQueueSize;
   1.303 +	}
   1.304 +
   1.305 +TBool CEventQueue::Expand(TWservEventPriorities aPriority)
   1.306 +	{
   1.307 +	if (iQueueSize==EMaxQueueSize)
   1.308 +		{
   1.309 +		if (aPriority==EEventPriorityHigh)
   1.310 +			{
   1.311 +			Purge();
   1.312 +			if (iCount<iQueueSize)
   1.313 +				return(ETrue);	// Success!
   1.314 +			}
   1.315 +		}
   1.316 +	else if (doExpand(ECompressNoPurge) ||
   1.317 +			  doExpand(ECompressPurge1) ||
   1.318 +			   (aPriority==EEventPriorityHigh && doExpand(ECompressPurge2)))
   1.319 +		return(ETrue);
   1.320 +	return(EFalse);				// Failure
   1.321 +	}
   1.322 +
   1.323 +TBool CEventQueue::doExpand(TCompressMode aCompressMode)
   1.324 +	{
   1.325 +	TDblQueIter<CEventQueue> iter(iQueueList);
   1.326 +	iter.SetToLast();
   1.327 +	CEventQueue* qptr=NULL;
   1.328 +	TInt spare=0;
   1.329 +	
   1.330 +	// while loop from last queue till current queue, moving all queues up 
   1.331 +	// to get all the space from between them
   1.332 +	while((qptr=iter)!=this)
   1.333 +		{
   1.334 +		spare=qptr->SqueezeUp();
   1.335 +		if (spare==0)
   1.336 +			qptr->Compress(aCompressMode);
   1.337 +		iter--;
   1.338 +		}
   1.339 +
   1.340 +	// current queue, if we have space then expand the same and return
   1.341 +	spare=FollowingGap();
   1.342 +	if (spare>0)
   1.343 +		{
   1.344 +		IncreaseQueueSize(spare);
   1.345 +		__CHECK_QUEUE();
   1.346 +		return(ETrue);
   1.347 +		}
   1.348 +
   1.349 +	// while loop from current queue till first queue, looking for a gap 
   1.350 +	// between queues and using the first one it finds
   1.351 +	iter--;
   1.352 +	TInt expanded=0;
   1.353 +	while((qptr=iter)!=NULL)
   1.354 +		{
   1.355 +		expanded=qptr->SqueezeUp();
   1.356 +		if (expanded>0)
   1.357 +			{
   1.358 +			return MoveDownAndExpand(iter, expanded);
   1.359 +			}
   1.360 +		else
   1.361 +			qptr->Compress(aCompressMode);
   1.362 +		iter--;
   1.363 +		}
   1.364 +
   1.365 +	// Even by doing all the above if we did not find space then check if first 
   1.366 +	// queue has some space before it. If so then make use of it and movedown all the 
   1.367 +	// queue till the current queue and then use the space for expansion
   1.368 +	iter.SetToFirst();
   1.369 +	qptr=iter;
   1.370 +	if (qptr->iEventPtr>iGlobalEventQueue)
   1.371 +		{
   1.372 +		return MoveDownAndExpand(iter, qptr->iEventPtr-iGlobalEventQueue);
   1.373 +		}
   1.374 +
   1.375 +	__CHECK_QUEUE();
   1.376 +	return(EFalse);	// Failed to expand enough room
   1.377 +	}
   1.378 +
   1.379 +// This function moves the queue down by given amount and repeats this until
   1.380 +// the current queue and then expand the same
   1.381 +TBool CEventQueue::MoveDownAndExpand(TDblQueIter<CEventQueue> &aIter, TInt aExpand)
   1.382 +	{
   1.383 +	CEventQueue* qptr=NULL;
   1.384 +	FOREVER
   1.385 +		{
   1.386 +		qptr=aIter++;
   1.387 +		qptr->MoveDown(aExpand);
   1.388 +		if (qptr==this)
   1.389 +			{
   1.390 +			IncreaseQueueSize(aExpand);
   1.391 +			__CHECK_QUEUE();
   1.392 +			break;
   1.393 +			}
   1.394 +		}
   1.395 +	return ETrue;
   1.396 +	}
   1.397 +
   1.398 +void CEventQueue::MoveDown(TInt aMove)
   1.399 +	{
   1.400 +	if (!aMove)
   1.401 +		{
   1.402 +		return;
   1.403 +		}
   1.404 +	EventCopy(iEventPtr-aMove,iEventPtr,iQueueSize);
   1.405 +	iEventPtr-=aMove;
   1.406 +	}
   1.407 +
   1.408 +/*void CEventQueue::LogUpDownEvents(TChar aChar)
   1.409 +	{
   1.410 +	TWsEvent *event;
   1.411 +	TBuf<128> buf;
   1.412 +	buf.Zero();
   1.413 +	buf.Append(aChar);
   1.414 +	buf.Append('#');
   1.415 +	buf.Append('#');
   1.416 +	TBool some=EFalse;
   1.417 +	TInt index;
   1.418 +
   1.419 +	for (index=0;index<iCount;index++)
   1.420 +		{
   1.421 +		event=EventPtr(index);
   1.422 +		if (event->Type()==EEventPointer)
   1.423 +			{
   1.424 +			if (event->Pointer()->iType==TPointerEvent::EButton1Down
   1.425 +										|| event->Pointer()->iType==TPointerEvent::EButton1Up)
   1.426 +				{
   1.427 +				some=ETrue;
   1.428 +				if (event->Pointer()->iType==TPointerEvent::EButton1Down)
   1.429 +					buf.Append('D');
   1.430 +				else
   1.431 +					buf.Append('U');
   1.432 +				buf.AppendNum(index);
   1.433 +				}
   1.434 +			}
   1.435 +		}
   1.436 +	if (wsDebugLog)
   1.437 +		wsDebugLog->MiscMessage(ELogImportant,buf);
   1.438 +	}*/
   1.439 +
   1.440 +inline void CEventQueue::IncEventPointer(TWsEvent*& aEventPtr)
   1.441 +	{
   1.442 +	// iEventPtr[iQueueSize] is the element beyond the array, used for efficient bounds checking of the circular buffer only, do not access!!
   1.443 +	if(++aEventPtr==&iEventPtr[iQueueSize])
   1.444 +		{
   1.445 +		aEventPtr=iEventPtr;
   1.446 +		}
   1.447 +	}
   1.448 +
   1.449 +inline void CEventQueue::DecEventPointer(TWsEvent*& aEventPtr)
   1.450 +	{
   1.451 +	if(aEventPtr--==iEventPtr)
   1.452 +		{
   1.453 +		aEventPtr=&iEventPtr[iQueueSize - 1];
   1.454 +		}
   1.455 +	}
   1.456 +
   1.457 +/*
   1.458 +Starting from aEventToPurge searches the queue for matching event by iterating towards end of queue.
   1.459 +Matching event will be a pointer event with the same window handle and pointer number
   1.460 +as aEventToPurge, but will have type aMatchingType. If matching event is found, it will 
   1.461 +be removed from the queue and search will finish.
   1.462 +
   1.463 +Search will be stopped if an event of type aSearchTerminator is found with the same pointer number 
   1.464 +as aEventToPurge.
   1.465 +
   1.466 +If search is not stopped by aSearchTerminator and matching event is not found, TWsPointer
   1.467 +class is notified that matching event has not been removed, so if it arrives in the future,
   1.468 +TWsPointer class will be able to ignore it.
   1.469 +*/
   1.470 +void CEventQueue::PurgeEventPairs(TWsEvent* aEventToPurge, TPointerEvent::TType aMatchingType, TPointerEvent::TType aSearchTerminator)
   1.471 +		{
   1.472 +		TWsEvent* eventToMatch = aEventToPurge;
   1.473 +		TWsEvent* lastEvent = EventPtr(iCount);
   1.474 +		for(IncEventPointer(eventToMatch);eventToMatch!=lastEvent;IncEventPointer(eventToMatch))
   1.475 +			{
   1.476 +			if ( (eventToMatch->Type()==EEventPointer)  // Must be checked first to ensure it is pointer data checked later
   1.477 +					&&	(TAdvancedPointerEventHelper::PointerNumber(*eventToMatch) == TAdvancedPointerEventHelper::PointerNumber(*aEventToPurge))) // same pointer 
   1.478 +				{
   1.479 +				if ((eventToMatch->Pointer()->iType==aMatchingType) // correct event type
   1.480 +						&& (eventToMatch->Handle()==aEventToPurge->Handle())) // same window
   1.481 +					{
   1.482 +					*eventToMatch=iNullEvent;
   1.483 +					return;
   1.484 +					}
   1.485 +				else if (eventToMatch->Pointer()->iType==aSearchTerminator) // stop searching for mathing type
   1.486 +					{
   1.487 +					return;
   1.488 +					}
   1.489 +				}
   1.490 +			};
   1.491 +		TWsPointer::UnmatchedEventPurged(aMatchingType, aEventToPurge);
   1.492 +		}
   1.493 +
   1.494 +/**
   1.495 +Starting from pointer event aBasePointerEvent searches the queue for next pointer event for 
   1.496 +the same pointer by iterating towards end of queue.
   1.497 +
   1.498 +@param aBasePointerEvent must be of type EEventPointer
   1.499 +@return Next pointer event in the queue for the same pointer as aBasePointerEvent 
   1.500 +        if it has the same handle as aBasePointerEvent or NULL if it has different handle.
   1.501 +        NULL if there is no next pointer event for the same pointer in the queue.
   1.502 +*/
   1.503 +TWsEvent* CEventQueue::NextPointerEvent(TWsEvent* aBasePointerEvent)
   1.504 +	{
   1.505 +	WS_ASSERT_DEBUG(aBasePointerEvent->Type() == EEventPointer, EWsPanicCheckEventQueue);
   1.506 +	TWsEvent* currentEvent = aBasePointerEvent;
   1.507 +	TWsEvent* lastEvent = EventPtr(iCount);
   1.508 +	TUint8 pointerNumber = TAdvancedPointerEventHelper::PointerNumber(*aBasePointerEvent);
   1.509 +	TUint handle = aBasePointerEvent->Handle();
   1.510 +	for(IncEventPointer(currentEvent);currentEvent!=lastEvent;IncEventPointer(currentEvent))
   1.511 +		{
   1.512 +		if ((currentEvent->Type() == EEventPointer) && 
   1.513 +			(TAdvancedPointerEventHelper::PointerNumber(*currentEvent) == pointerNumber))
   1.514 +			{
   1.515 +			if (currentEvent->Handle() == handle)
   1.516 +				{
   1.517 +				return currentEvent;
   1.518 +				}
   1.519 +			else
   1.520 +				{
   1.521 +				return NULL;
   1.522 +				}
   1.523 +			}
   1.524 +		};
   1.525 +	return NULL;
   1.526 +	}
   1.527 +	
   1.528 +/**
   1.529 +Checks if aEventToPurge should be purged. If it can be purged, then events that should
   1.530 +be purged together with aEventToPurge (matching events) are overwritten with iNullEvent.
   1.531 +
   1.532 +@return ETrue if aEventToPurge should be purged, EFalse otherwise.
   1.533 +*/
   1.534 +TBool CEventQueue::CheckPurgePointerEvent(TWsEvent* aEventToPurge)
   1.535 +	{
   1.536 +	switch(aEventToPurge->Pointer()->iType)
   1.537 +		{
   1.538 +		case TPointerEvent::EDrag:
   1.539 +		case TPointerEvent::EMove:
   1.540 +		case TPointerEvent::EButtonRepeat:
   1.541 +		case TPointerEvent::ESwitchOn:
   1.542 +			return ETrue;
   1.543 +		case TPointerEvent::EButton1Down:
   1.544 +			PurgeEventPairs(aEventToPurge,TPointerEvent::EButton1Up, TPointerEvent::ENullType);
   1.545 +			return ETrue;
   1.546 +		case TPointerEvent::EButton2Down:
   1.547 +			PurgeEventPairs(aEventToPurge,TPointerEvent::EButton2Up, TPointerEvent::ENullType);
   1.548 +			return ETrue;
   1.549 +		case TPointerEvent::EButton3Down:
   1.550 +			PurgeEventPairs(aEventToPurge,TPointerEvent::EButton3Up, TPointerEvent::ENullType);
   1.551 +			return ETrue;
   1.552 +		case TPointerEvent::EEnterHighPressure:
   1.553 +			PurgeEventPairs(aEventToPurge,TPointerEvent::EExitHighPressure, TPointerEvent::EButton1Up);
   1.554 +			return ETrue;
   1.555 +		case TPointerEvent::EEnterCloseProximity:
   1.556 +			{
   1.557 +			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
   1.558 +			if (nextEvent != NULL)
   1.559 +				{
   1.560 +				switch(nextEvent->Pointer()->iType)
   1.561 +					{
   1.562 +					case TPointerEvent::EExitCloseProximity: 
   1.563 +						*nextEvent = iNullEvent;
   1.564 +					case TPointerEvent::EOutOfRange:
   1.565 +						return ETrue;
   1.566 +					}
   1.567 +				}
   1.568 +			break;
   1.569 +			}
   1.570 +		case TPointerEvent::EExitCloseProximity:
   1.571 +			{
   1.572 +			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
   1.573 +			if (nextEvent != NULL)
   1.574 +				{
   1.575 +				switch(nextEvent->Pointer()->iType)
   1.576 +					{
   1.577 +					case TPointerEvent::EEnterCloseProximity: 
   1.578 +						*nextEvent = iNullEvent;
   1.579 +					case TPointerEvent::EOutOfRange:
   1.580 +						return ETrue;
   1.581 +					}
   1.582 +				}
   1.583 +			break;
   1.584 +			}
   1.585 +		case TPointerEvent::EOutOfRange:
   1.586 +			{
   1.587 +			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
   1.588 +			if ((nextEvent != NULL) &&
   1.589 +				(nextEvent->Pointer()->iType == TPointerEvent::EOutOfRange))
   1.590 +				{
   1.591 +				return ETrue;
   1.592 +				}
   1.593 +			break;
   1.594 +			}
   1.595 +		case TPointerEvent::EExitHighPressure:
   1.596 +			{
   1.597 +			TWsEvent* nextEvent = NextPointerEvent(aEventToPurge);
   1.598 +			if ((nextEvent != NULL) &&
   1.599 +				(nextEvent->Pointer()->iType == TPointerEvent::EButton1Up))
   1.600 +				{
   1.601 +				return ETrue;
   1.602 +				}
   1.603 +			break;
   1.604 +			}
   1.605 +		case TPointerEvent::EButton1Up:
   1.606 +		case TPointerEvent::EButton2Up:
   1.607 +		case TPointerEvent::EButton3Up:
   1.608 +			break;
   1.609 +		}
   1.610 +	return EFalse;
   1.611 +	}
   1.612 +
   1.613 +/** Purgable events are:
   1.614 +	Pointer Up/Down pairs belonging to the same pointer, button and window
   1.615 +    Pointer moves & drags
   1.616 +    Key messages
   1.617 +    Key Up/Down pairs
   1.618 +    Key Ups if not foreground connection
   1.619 +    Focus lost/gained pairs
   1.620 +    EEnterHighPressure/EExitHighPressure pairs belonging to the same pointer
   1.621 +    EEnterCloseProximity/EExitCloseProximity pairs belonging to the same pointer
   1.622 +    Lone EEnterHighPressure, EExitHighPressure if followed by Up for the same pointer
   1.623 +    Lone EEnterCloseProximity, EExitCloseProximity if followed by EOutOfRange for the same pointer
   1.624 +    EOutOfRange if followed by another EOutOfRange for the same pointer
   1.625 +
   1.626 +    Events that must not be purged:
   1.627 +    Key ups for foreground connections queue
   1.628 +    Lone pointer ups, must be delivered to match preceeding pointer down
   1.629 +    Lone EExitHighPressure if not followed by Up, must be delivered to match preceeding EEnterHighPressure
   1.630 +    Lone EEnterCloseProximity, EExitCloseProximity not followed by EOutOfRange for the same pointer
   1.631 +    Lone focus lost/gained messages
   1.632 +*/	
   1.633 +void CEventQueue::Purge()
   1.634 +	{
   1.635 +	TWsEvent* eventToPurge;
   1.636 +	TWsEvent* eventToMatch;
   1.637 +	TInt indexToMatch;
   1.638 +	TInt indexToPurge=iCount;
   1.639 +	while(indexToPurge>0)
   1.640 +		{
   1.641 +		eventToPurge=EventPtr(--indexToPurge);
   1.642 +		switch(eventToPurge->Type())
   1.643 +			{
   1.644 +			case EEventPassword:
   1.645 +				break;
   1.646 +			case EEventMarkInvalid:
   1.647 +#if defined(_DEBUG)
   1.648 +				WS_PANIC_DEBUG(EWsPanicCheckEventQueue);
   1.649 +#endif
   1.650 +			case EEventNull:
   1.651 +			case EEventKey:
   1.652 +			case EEventPointerEnter:
   1.653 +			case EEventPointerExit:
   1.654 +			case EEventDragDrop:
   1.655 +breakLoopAndRemoveEvent:
   1.656 +#ifdef LOG_WSERV_EVENTS
   1.657 +				RDebug::Print(_L("_WSEVENT: CEventQueue::Purge(), The event to be purged is %S"), &WsEventName(*eventToPurge));
   1.658 +#endif
   1.659 +				RemoveEvent(indexToPurge);
   1.660 +				return;
   1.661 +			case EEventKeyUp:
   1.662 +				if (iQueueList.First()!=this)
   1.663 +					goto breakLoopAndRemoveEvent;
   1.664 +				break;
   1.665 +			case EEventKeyDown:
   1.666 +				if (iQueueList.First()!=this)
   1.667 +					goto breakLoopAndRemoveEvent;
   1.668 +				for (indexToMatch=indexToPurge+1;indexToMatch<iCount;indexToMatch++)
   1.669 +					{
   1.670 +					eventToMatch=EventPtr(indexToMatch);
   1.671 +					if (eventToMatch->Type()==EEventKeyUp && eventToMatch->Key()->iScanCode==eventToPurge->Key()->iScanCode)
   1.672 +						{
   1.673 +						*eventToMatch=iNullEvent;
   1.674 +						goto breakLoopAndRemoveEvent;
   1.675 +						}
   1.676 +					}
   1.677 +				break;
   1.678 +			case EEventModifiersChanged:
   1.679 +				for (indexToMatch=indexToPurge;indexToMatch>0;)
   1.680 +					{
   1.681 +					eventToMatch=EventPtr(--indexToMatch);
   1.682 +					if (eventToMatch->Type()==EEventModifiersChanged)
   1.683 +						{
   1.684 +						eventToPurge->ModifiersChanged()->iChangedModifiers|=eventToMatch->ModifiersChanged()->iChangedModifiers;
   1.685 +						indexToPurge=indexToMatch;
   1.686 +						goto breakLoopAndRemoveEvent;
   1.687 +						}
   1.688 +					}
   1.689 +				break;
   1.690 +			case EEventPointerBufferReady:
   1.691 +				CWsPointerBuffer::DiscardPointerMoveBuffer(eventToPurge->Handle());
   1.692 +				goto breakLoopAndRemoveEvent;
   1.693 +			case EEventFocusLost:
   1.694 +			case EEventFocusGained:
   1.695 +				if ((indexToPurge+1)<iCount)
   1.696 +					{
   1.697 +					eventToMatch=EventPtr(indexToPurge+1);
   1.698 +					if (eventToMatch->Type()==EEventFocusLost || eventToMatch->Type()==EEventFocusGained)
   1.699 +						{
   1.700 +						*eventToMatch=iNullEvent;
   1.701 +						goto breakLoopAndRemoveEvent;
   1.702 +						}
   1.703 +					}
   1.704 +				break;
   1.705 +			case EEventSwitchOn:
   1.706 +				if ((indexToPurge+1)<iCount && EventPtr(indexToPurge+1)->Type()==EEventSwitchOn)
   1.707 +					goto breakLoopAndRemoveEvent;
   1.708 +				break;
   1.709 +			case EEventPointer:
   1.710 +				if (CheckPurgePointerEvent(eventToPurge))
   1.711 +					{
   1.712 +					goto breakLoopAndRemoveEvent;
   1.713 +					}
   1.714 +				break;
   1.715 +			}
   1.716 +		}
   1.717 +	}
   1.718 +
   1.719 +void CEventQueue::PurgePointerEvents()
   1.720 +	{
   1.721 +	TWsEvent* eventToPurge;
   1.722 +	TInt indexToPurge=iCount;
   1.723 +	while(indexToPurge>0)
   1.724 +		{
   1.725 +		eventToPurge=EventPtr(--indexToPurge);
   1.726 +		switch(eventToPurge->Type())
   1.727 +			{
   1.728 +			case EEventPointerBufferReady:
   1.729 +				CWsPointerBuffer::DiscardPointerMoveBuffer(eventToPurge->Handle());
   1.730 +				RemoveEvent(indexToPurge);
   1.731 +				break;
   1.732 +			case EEventPointer:
   1.733 +				if (CheckPurgePointerEvent(eventToPurge))
   1.734 +					{
   1.735 +					RemoveEvent(indexToPurge);
   1.736 +					}
   1.737 +				break;
   1.738 +			}
   1.739 +		}
   1.740 +	}
   1.741 +
   1.742 +/**
   1.743 +Purge requested number of oldest events from inactive event queue.
   1.744 +@param aSizeRequired the total events required to be cleared. 
   1.745 +@return The number of events cleared.
   1.746 +*/
   1.747 +TInt CEventQueue::PurgeInactiveEvents(const TInt& aSizeRequired)
   1.748 +	{
   1.749 +	TInt numEventsCleared = 0;
   1.750 +	CEventQueue* qptr;
   1.751 +	TBool isRemoved;
   1.752 +	do	{
   1.753 +		TDblQueIter<CEventQueue> iter(iQueueList);
   1.754 +		isRemoved = EFalse;
   1.755 +		while ((qptr = iter++) != NULL && (aSizeRequired > numEventsCleared))
   1.756 +			{
   1.757 +			if ((qptr->IsEventCancelled() || (qptr->iEventMsg.IsNull() && !qptr->iEventSignalledState)) &&
   1.758 +				(qptr->iQueueSize > EMinQueueSize))
   1.759 +				{
   1.760 +				// we have a client that is not listening with a size larger than min queue size.
   1.761 +				// so lets remove it's oldest event until the number of removed events meet the requirement.
   1.762 +				qptr->RemoveEvent(0);
   1.763 +				numEventsCleared++;
   1.764 +				isRemoved = ETrue;
   1.765 +				}
   1.766 +			}
   1.767 +		} while ((aSizeRequired > numEventsCleared) && isRemoved);
   1.768 +	return numEventsCleared;
   1.769 +	}
   1.770 +
   1.771 +void CEventQueue::Compress(TCompressMode aCompressMode)
   1.772 +	{
   1.773 +//
   1.774 +// The different purge modes are
   1.775 +//
   1.776 +// ECompressNoPurge,	// Don't purge anything
   1.777 +// ECompressPurge1,		// Don't purge foreground queue
   1.778 +// ECompressPurge2,		// Purge all queues
   1.779 +//
   1.780 +	if (aCompressMode==ECompressPurge2 ||
   1.781 +		(this!=iQueueList.First() && aCompressMode==ECompressPurge1))
   1.782 +		Purge();
   1.783 +	TInt compress=iQueueSize-(iCount>EMinQueueSize?iCount:EMinQueueSize);
   1.784 +	if (compress>0)
   1.785 +		{
   1.786 +		compress=(compress+1)/2;	// Compress half the free space in the queue
   1.787 +		TWsEvent* head=EventPtr(0);
   1.788 +		TWsEvent* tail=EventPtr(iCount);
   1.789 +		if (head>tail)
   1.790 +			{
   1.791 +			EventCopy(iEventPtr+compress,iEventPtr,tail-iEventPtr);
   1.792 +			iHead-=compress;
   1.793 +			}
   1.794 +		else
   1.795 +			{
   1.796 +			EventCopy(iEventPtr+compress,head,iCount);
   1.797 +			iHead=0;
   1.798 +			}
   1.799 +		iEventPtr+=compress;
   1.800 +		iQueueSize-=compress;
   1.801 +		}
   1.802 +	}
   1.803 +
   1.804 +void CEventQueue::MoveUp(TInt aNumEvents)
   1.805 +	{
   1.806 +	if (!aNumEvents)
   1.807 +		{
   1.808 +		return;
   1.809 +		}
   1.810 +	EventCopy(iEventPtr+aNumEvents,iEventPtr,iQueueSize);
   1.811 +	iEventPtr+=aNumEvents;
   1.812 +	}
   1.813 +
   1.814 +TInt CEventQueue::FollowingGap() const
   1.815 +	{
   1.816 +	TDblQueIter<CEventQueue> iter(iQueueList);
   1.817 +	CEventQueue* qptr;
   1.818 +	iter.Set(*(CEventQueue *)this);
   1.819 +	iter++;
   1.820 +	TWsEvent* end;
   1.821 +	if ((qptr=iter)!=NULL)
   1.822 +		end=qptr->iEventPtr;
   1.823 +	else
   1.824 +		end=iGlobalEventQueue+iGlobalEventQueueSize;
   1.825 +	return(end-(iEventPtr+iQueueSize));
   1.826 +	}
   1.827 +
   1.828 +TInt CEventQueue::SqueezeUp()
   1.829 +	{
   1.830 +	TInt gap=FollowingGap();
   1.831 +	MoveUp(gap);
   1.832 +	return(gap);
   1.833 +	}
   1.834 +
   1.835 +void CEventQueue::SqueezeDown()
   1.836 +	{
   1.837 +	TDblQueIter<CEventQueue> iter(iQueueList);
   1.838 +	iter.Set(*this);
   1.839 +	iter--;
   1.840 +	CEventQueue* qptr=iter;
   1.841 +	if (qptr!=NULL)
   1.842 +		{
   1.843 +		Compress(ECompressNoPurge);
   1.844 +		TInt gap=qptr->FollowingGap();
   1.845 +		MoveDown(gap);
   1.846 +		}
   1.847 +	}
   1.848 +
   1.849 +void CEventQueue::MoveToFront()
   1.850 +	{
   1.851 +	if (this==iQueueList.First())
   1.852 +		return;
   1.853 +	Wait();
   1.854 +	CEventQueue* qptr;
   1.855 +	TInt gap=0;
   1.856 +	TDblQueIter<CEventQueue> iter(iQueueList);
   1.857 +	iter.SetToLast();
   1.858 +	while((qptr=iter--)!=NULL)
   1.859 +		{
   1.860 +		if (gap<iQueueSize)
   1.861 +			qptr->Compress(ECompressNoPurge);
   1.862 +		gap=qptr->SqueezeUp();
   1.863 +		}
   1.864 +	if (gap>=iQueueSize)
   1.865 +		EventCopy(iGlobalEventQueue,iEventPtr,iQueueSize);
   1.866 +	else
   1.867 +		{
   1.868 +		EventCopy(iGlobalEventQueue,iEventPtr,gap);
   1.869 +		iEventPtr+=gap;
   1.870 +		TWsEvent copyBuf[ECopyBufSize];	// temp buffer, can copy upto ECopyBufSize events at a time
   1.871 +		TInt eventsToGo=iQueueSize-gap;
   1.872 +		iQueueSize=gap;
   1.873 +		do
   1.874 +			{
   1.875 +			TInt copy=Min(eventsToGo,ECopyBufSize);
   1.876 +			Mem::Copy(&copyBuf[0],iEventPtr,copy*sizeof(TWsEvent));
   1.877 +			iter.Set(*this);
   1.878 +			iter--;
   1.879 +			while((qptr=iter--)!=NULL)
   1.880 +				qptr->MoveUp(copy);
   1.881 +			EventCopy(iGlobalEventQueue+iQueueSize,&copyBuf[0],copy);
   1.882 +			iQueueSize+=copy;
   1.883 +			eventsToGo-=copy;
   1.884 +			iEventPtr+=copy;
   1.885 +			} while(eventsToGo>0);
   1.886 +		}
   1.887 +	iEventPtr=iGlobalEventQueue;
   1.888 +	this->iLink.Deque();
   1.889 +	iQueueList.AddFirst(*this);
   1.890 +	__CHECK_QUEUE();
   1.891 +	Signal();
   1.892 +	}
   1.893 +
   1.894 +// CEventQueue
   1.895 +
   1.896 +CEventQueue::CEventQueue(CWsClient* aOwner) : CEventBase(aOwner)
   1.897 +	{
   1.898 +	__DECLARE_NAME(_S("CEventQueue"));
   1.899 +	}
   1.900 +
   1.901 +CEventQueue::~CEventQueue()
   1.902 +	{
   1.903 +	RemoveQueue();
   1.904 +	}
   1.905 +
   1.906 +void CEventQueue::InitStaticsL()
   1.907 +	{
   1.908 +	User::LeaveIfError(iMutex.CreateLocal());
   1.909 +	}
   1.910 +
   1.911 +void CEventQueue::DeleteStaticsL()
   1.912 +	{
   1.913 +	iMutex.Close();
   1.914 +	}
   1.915 +
   1.916 +void CEventQueue::ConstructL()
   1.917 +	{
   1.918 +	AddQueueL();
   1.919 +	Mem::FillZ(&iNullEvent,sizeof(iNullEvent));
   1.920 +	}
   1.921 +
   1.922 +TWsEvent* CEventQueue::EventPtr(TInt index)	
   1.923 +	{
   1.924 +	return(iEventPtr+((iHead+index)%iQueueSize));
   1.925 +	}
   1.926 +
   1.927 +TBool CEventQueue::QueueEvent(const TWsEvent &event)
   1.928 +	{
   1.929 +	TWservEventPriorities priority=EEventPriorityLow;
   1.930 +#ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP
   1.931 +	if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || 
   1.932 +		event.Type()==EEventKeySwitchOff || event.Type()==EEventRestartSystem)
   1.933 +#else
   1.934 +	if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || event.Type()==EEventKeySwitchOff)
   1.935 +#endif
   1.936 +		{
   1.937 +		priority=EEventPriorityHigh;
   1.938 +		}
   1.939 +	return(QueueEvent(event,priority));
   1.940 +	}
   1.941 +
   1.942 +TBool CEventQueue::CheckRoom()
   1.943 +//
   1.944 +// If the queue is full and room is created return ETrue
   1.945 +//
   1.946 +	{
   1.947 +	TBool ret=EFalse;
   1.948 +	Wait();
   1.949 +	if (iCount==iQueueSize && Expand(EEventPriorityHigh))
   1.950 +		ret=ETrue;
   1.951 +	Signal();
   1.952 +	return(ret);
   1.953 +	}
   1.954 +
   1.955 +TBool CEventQueue::QueueEvent(const TWsEvent &event, TWservEventPriorities aPriority)
   1.956 +//
   1.957 +// Queue an event, returns ETrue if queued or delivered, EFalse if the queue was full.
   1.958 +//
   1.959 +	{
   1.960 +	TBool ret=ETrue;
   1.961 +	Wait();
   1.962 +	if (iCount==iQueueSize && !Expand(aPriority))
   1.963 +		{
   1.964 +		ret=EFalse;
   1.965 +#ifdef LOG_WSERV_EVENTS
   1.966 +		RDebug::Printf("WSEVENT: CEventQueue::QueueEvent(): 0x%X:  Queue Full!!!!!, iCount = %d, iQueueSize = %d", this, iCount, iQueueSize);
   1.967 +		RDebug::Print(_L("WSEVENT: CEventQueue::QueueEvent(): 0x%X:  Queue Full!!!!! TWsEvent.Type() = %S"), this, &WsEventName(event));
   1.968 +#endif
   1.969 +		}
   1.970 +	else
   1.971 +		{
   1.972 +		if (!iEventMsg.IsNull())
   1.973 +			{
   1.974 +			SignalEvent();
   1.975 +			}
   1.976 +#ifdef LOG_WSERV_EVENTS
   1.977 +		RDebug::Printf("_WSEVENT: CEventQueue::QueueEvent, Right before adding the event");
   1.978 +#endif
   1.979 +		*EventPtr(iCount++)=event;
   1.980 +#ifdef LOG_WSERV_EVENTS
   1.981 +		RDebug::Print(_L("_WSEVENT: CEventQueue::QueueEvent, Event %S successfully queued"), &WsEventName(event));
   1.982 +#endif
   1.983 +		}
   1.984 +	Signal();
   1.985 +	return(ret);
   1.986 +	}
   1.987 +
   1.988 +TBool CEventQueue::QueueEvent(TUint32 aTarget, TInt aEvent, TInt aIntVal)
   1.989 +	{
   1.990 +	TWsEvent event;
   1.991 +	event.SetType(aEvent);
   1.992 +	event.SetHandle(aTarget);
   1.993 +	event.SetTimeNow();
   1.994 +	*(event.Int()) = aIntVal;
   1.995 +	return(QueueEvent(event));
   1.996 +	}
   1.997 +
   1.998 +void CEventQueue::UpdateLastEvent(const TWsEvent &event)
   1.999 +	{
  1.1000 +	WS_ASSERT_DEBUG(iCount>0, EWsPanicQueueUpdateCount);
  1.1001 +	Mem::Copy(EventPtr(iCount-1)->EventData(),event.EventData(),TWsEvent::EWsEventDataSize);
  1.1002 +	}
  1.1003 +
  1.1004 +/*
  1.1005 +Replaces last pointer event related to particular pointer with new one.
  1.1006 +
  1.1007 +While searching for event to replace this method considers all events on the
  1.1008 +queue except EMove and EDrag pointer events from pointers different than aEvent. 
  1.1009 +If the last of these events under consideration:
  1.1010 +(1) is a pointer event, 
  1.1011 +(2) has the same type as aEvent,
  1.1012 +(3) its type is either EMove or EDrag and
  1.1013 +(4) has the same window handle as aEvent,
  1.1014 +then it is removed from the queue and aEvent is put at the end of the queue.
  1.1015 +
  1.1016 +@return ETrue if event on the queue has been replaced with aEvent, EFalse otherwise. 
  1.1017 +*/
  1.1018 +TBool CEventQueue::UpdateLastPointerEvent(const TWsEvent &aEvent)
  1.1019 +	{
  1.1020 +	if (aEvent.Pointer()->iType == TPointerEvent::EMove || aEvent.Pointer()->iType == TPointerEvent::EDrag)
  1.1021 +		{
  1.1022 +		Wait();
  1.1023 +		
  1.1024 +		if (iCount == 0)
  1.1025 +			{
  1.1026 +			Signal();
  1.1027 +			return EFalse;
  1.1028 +			}
  1.1029 +		
  1.1030 +		// loop through all events on the queue starting from the last one
  1.1031 +		TWsEvent* evToUpdate = EventPtr(iCount);
  1.1032 +		TWsEvent* evOnHead   = &iEventPtr[iHead]; 
  1.1033 +		while (evToUpdate != evOnHead)
  1.1034 +			{
  1.1035 +			DecEventPointer(evToUpdate);
  1.1036 +			
  1.1037 +			// conditions that stop searching
  1.1038 +			if (   (evToUpdate->Type() != EEventPointer)	// found non-pointer event
  1.1039 +				|| (evToUpdate->Pointer()->iType != TPointerEvent::EMove && evToUpdate->Pointer()->iType != TPointerEvent::EDrag)	// pointer event but wrong type
  1.1040 +				|| (   (TAdvancedPointerEventHelper::PointerNumber(*evToUpdate) == TAdvancedPointerEventHelper::PointerNumber(aEvent))
  1.1041 +				    && (   (evToUpdate->Handle() != aEvent.Handle())					// good number & bad handle         
  1.1042 +				        || (evToUpdate->Pointer()->iType != aEvent.Pointer()->iType)))) // good number & bad type
  1.1043 +				{
  1.1044 +				Signal();
  1.1045 +				return EFalse;
  1.1046 +				}
  1.1047 +			else if (TAdvancedPointerEventHelper::PointerNumber(*evToUpdate) == TAdvancedPointerEventHelper::PointerNumber(aEvent))
  1.1048 +				{
  1.1049 +				// we found event to update: evToUpdate is pointer event with right type, pointer number
  1.1050 +				// and window handle
  1.1051 +				
  1.1052 +				if (evToUpdate == EventPtr(iCount - 1))
  1.1053 +					{
  1.1054 +					UpdateLastEvent(aEvent);
  1.1055 +					}
  1.1056 +				else
  1.1057 +					{
  1.1058 +					RemoveEvent(evToUpdate);
  1.1059 +					*EventPtr(iCount++) = aEvent;
  1.1060 +					}
  1.1061 +				Signal();
  1.1062 +				return ETrue;
  1.1063 +				}
  1.1064 +			
  1.1065 +			// evToUpdate is EMove or EDrag pointer event with different pointer id,
  1.1066 +			// continue to loop through the queue
  1.1067 +			}
  1.1068 +		Signal();
  1.1069 +		}
  1.1070 +	return EFalse;
  1.1071 +	}
  1.1072 +
  1.1073 +void CEventQueue::GetData()
  1.1074 +//
  1.1075 +// If there is an outstanding event in the queue, reply with it's data and remove it from the Q
  1.1076 +//
  1.1077 +	{
  1.1078 +	if (iCount>0)
  1.1079 +		{
  1.1080 +		WS_ASSERT_DEBUG((iEventPtr+iHead)->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
  1.1081 +		CEventBase::GetData(iEventPtr+iHead,sizeof(*iEventPtr));
  1.1082 +#ifdef LOG_WSERV_EVENTS
  1.1083 +		RDebug::Printf("_WSEVENT: CEventQueue::GetData(), TWsEvent.Type() = %d", (iEventPtr+iHead)->Type());
  1.1084 +#endif
  1.1085 +		__ZAP_EVENT(iEventPtr+iHead);
  1.1086 +		iHead=(iHead+1)%iQueueSize;
  1.1087 +		iCount--;
  1.1088 +		}
  1.1089 +	else
  1.1090 +		CEventBase::GetData(&iNullEvent,sizeof(iNullEvent));
  1.1091 +	}
  1.1092 +
  1.1093 +void CEventQueue::EventReady(const RMessagePtr2& aEventMsg)
  1.1094 +//
  1.1095 +// Queue a read of an event notification
  1.1096 +//
  1.1097 +	{
  1.1098 +	EventReadyCheck();
  1.1099 +	Wait();
  1.1100 +	iEventMsg=aEventMsg;
  1.1101 +	if (iCount>0)
  1.1102 +		SignalEvent();
  1.1103 +	Signal();
  1.1104 +	}
  1.1105 +
  1.1106 +void CEventQueue::RemoveEvent(TInt index)
  1.1107 +//
  1.1108 +// Remove event 'index' in the queue, this event MUST exist in the queue
  1.1109 +//
  1.1110 +	{
  1.1111 +#ifdef LOG_WSERV_EVENTS
  1.1112 +	RDebug::Printf("_WSEVENT: CEventQueue::RemoveEvent(index), Remove event index %d in the queue", index);
  1.1113 +#endif
  1.1114 +	WS_ASSERT_DEBUG(index < iCount, EWsPanicCheckEventQueue);
  1.1115 +	RemoveEvent(EventPtr(index));
  1.1116 +	}
  1.1117 +
  1.1118 +void CEventQueue::RemoveEvent(TWsEvent* aEvToRemove)
  1.1119 +//
  1.1120 +// Remove event in the queue, this event MUST exist in the queue
  1.1121 +//
  1.1122 +	{
  1.1123 +#ifdef LOG_WSERV_EVENTS
  1.1124 +	RDebug::Print(_L("_WSEVENT: CEventQueue::RemoveEvent(aEvToRemove), Remove event %S in the queue"), &WsEventName(*aEvToRemove));
  1.1125 +#endif
  1.1126 +	iCount--;
  1.1127 +	TWsEvent* last = EventPtr(iCount);
  1.1128 +	TWsEvent* prev;
  1.1129 +	while(aEvToRemove!=last)
  1.1130 +		{
  1.1131 +		prev = aEvToRemove;
  1.1132 +		IncEventPointer(aEvToRemove);
  1.1133 +		*prev = *aEvToRemove;
  1.1134 +		}
  1.1135 +	__ZAP_EVENT(last);
  1.1136 +	}
  1.1137 +
  1.1138 +const TWsEvent* CEventQueue::PeekLastEvent()
  1.1139 +//
  1.1140 +// Return a read only pointer to the last event in the queue (or NULL if no event)
  1.1141 +//
  1.1142 +	{
  1.1143 +	if (iCount==0)
  1.1144 +		return(NULL);
  1.1145 +	return(EventPtr(iCount-1));
  1.1146 +	}
  1.1147 +
  1.1148 +void CEventQueue::Wait()
  1.1149 +	{
  1.1150 +	iMutex.Wait();
  1.1151 +	}
  1.1152 +
  1.1153 +void CEventQueue::Signal()
  1.1154 +	{
  1.1155 +	iMutex.Signal();
  1.1156 +	}
  1.1157 +
  1.1158 +void CEventQueue::WalkEventQueue(EventQueueWalk aFunc, TAny* aFuncParam)
  1.1159 +	{
  1.1160 +	Wait();
  1.1161 +restart:
  1.1162 +	for (TInt index=0;index<iCount;index++)
  1.1163 +		{
  1.1164 +		TWsEvent* event=EventPtr(index);
  1.1165 +		switch((aFunc)(aFuncParam,event))
  1.1166 +			{
  1.1167 +			case EEventQueueWalkDeleteEvent:
  1.1168 +				RemoveEvent(index--);
  1.1169 +			case EEventQueueWalkOk:
  1.1170 +				break;
  1.1171 +			case EEventQueueWalkRestart:
  1.1172 +				goto restart;
  1.1173 +			}
  1.1174 +		}
  1.1175 +	Signal();
  1.1176 +	}