sl@0: // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Window server event queue handling sl@0: // sl@0: // sl@0: sl@0: #include "EVQUEUE.H" sl@0: sl@0: #include "server.h" sl@0: #include "wstop.h" sl@0: #include "panics.h" sl@0: #include "pointer.h" sl@0: #include "advancedpointereventhelper.h" sl@0: #include "debughelper.h" sl@0: sl@0: GLREF_D CDebugLogBase* wsDebugLog; sl@0: sl@0: #if defined(_DEBUG) sl@0: #define __CHECK_QUEUE() CheckQueue() sl@0: #define __ZAP_EVENTS(pointer,len) ZapEvents(pointer,len) sl@0: #define __ZAP_EVENT(pointer) ZapEvent(pointer) sl@0: #else sl@0: #define __CHECK_QUEUE() sl@0: #define __ZAP_EVENTS(pointer,len) sl@0: #define __ZAP_EVENT(pointer) sl@0: #endif sl@0: sl@0: const TInt ECopyBufSize=4; sl@0: sl@0: TDblQue CEventQueue::iQueueList(_FOFF(CEventQueue,iLink)); sl@0: TWsEvent* CEventQueue::iGlobalEventQueue=NULL; sl@0: TInt CEventQueue::iGlobalEventQueueSize=0; sl@0: TInt CEventQueue::iNumConnections=0; sl@0: RMutex CEventQueue::iMutex; sl@0: TWsEvent CEventQueue::iNullEvent; sl@0: sl@0: // CEventBase sl@0: sl@0: CEventBase::~CEventBase() sl@0: { sl@0: if (!iEventMsg.IsNull() && CWsTop::ShuttingDown()) sl@0: { sl@0: iEventMsg.Complete(KErrServerTerminated); sl@0: } sl@0: } sl@0: sl@0: CEventBase::CEventBase(CWsClient* aOwner) : iWsOwner(aOwner) sl@0: { sl@0: } sl@0: sl@0: void CEventBase::SignalEvent(TInt aCode) sl@0: { sl@0: if (wsDebugLog) sl@0: wsDebugLog->SignalEvent(iWsOwner->ConnectionHandle()); sl@0: iEventMsg.Complete(aCode); sl@0: iEventSignalledState|=EEventFlagSignalled; sl@0: } sl@0: sl@0: inline TBool CEventBase::IsEventCancelled() sl@0: { sl@0: return (iEventSignalledState & EEventFlagCancelled); sl@0: } sl@0: sl@0: /** sl@0: If there is an outstanding read cancel it. sl@0: */ sl@0: void CEventBase::CancelRead() sl@0: { sl@0: if (!iEventMsg.IsNull()) sl@0: { sl@0: iEventMsg.Complete(KErrCancel); sl@0: } sl@0: iEventSignalledState|=EEventFlagCancelled; sl@0: } sl@0: sl@0: void CEventBase::GetData(TAny* aData, TInt aLen) sl@0: { sl@0: if (!(iEventSignalledState&EEventFlagSignalled)) sl@0: { sl@0: iWsOwner->PPanic(EWservPanicUnsignalledEventData); sl@0: } sl@0: iEventSignalledState&=~EEventFlagSignalled; sl@0: CWsClient::ReplyBuf(aData,aLen); sl@0: } sl@0: sl@0: /** sl@0: Queue a read of an event notification sl@0: */ sl@0: void CEventBase::EventReadyCheck() sl@0: { sl@0: if ((iEventSignalledState&EEventFlagSignalled && !(iEventSignalledState&EEventFlagCancelled)) || !iEventMsg.IsNull()) sl@0: { sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Printf("_WSEVENT: CEventBase::EventReadyCheck, Event is not ready"); sl@0: #endif sl@0: iWsOwner->PPanic(EWservPanicReadOutstanding); sl@0: } sl@0: } sl@0: sl@0: void CEventBase::EventReady(const RMessagePtr2& aEventMsg) sl@0: { sl@0: EventReadyCheck(); sl@0: iEventMsg=aEventMsg; sl@0: } sl@0: sl@0: // CEventQueue - Queue organisation functions sl@0: sl@0: #if defined(_DEBUG) sl@0: void CEventQueue::CheckQueue() sl@0: { sl@0: TDblQueIter iter(iQueueList); sl@0: CEventQueue* qptr; sl@0: iter.SetToFirst(); sl@0: while((qptr=iter++)!=NULL) sl@0: { sl@0: WS_ASSERT_DEBUG(qptr->iQueueSize>=0 && qptr->iQueueSize<=iGlobalEventQueueSize, EWsPanicCheckEventQueue); sl@0: WS_ASSERT_DEBUG(qptr->iQueueSize==0 || qptr->iHeadiQueueSize, EWsPanicCheckEventQueue); sl@0: WS_ASSERT_DEBUG(qptr->iCount<=qptr->iQueueSize, EWsPanicCheckEventQueue); sl@0: WS_ASSERT_DEBUG(qptr->iEventPtr>=iGlobalEventQueue && qptr->iEventPtr<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicCheckEventQueue); sl@0: } sl@0: for(TInt index=0;indexType()!=EEventMarkInvalid, EWsPanicCheckEventQueue); sl@0: } sl@0: } sl@0: sl@0: void CEventQueue::ZapEvent(TWsEvent* aTarget) sl@0: { sl@0: aTarget->SetType(EEventMarkInvalid); sl@0: aTarget->SetHandle(555); sl@0: } sl@0: sl@0: void CEventQueue::ZapEvents(TWsEvent* aTarget, TInt aLen) sl@0: { sl@0: for(TInt index=0;index=iGlobalEventQueue, EWsPanicEventQueueCopy); sl@0: WS_ASSERT_DEBUG((aTarget+aNumEvents)<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicEventQueueCopy); sl@0: Mem::Copy(aTarget,aSource,aNumEvents*sizeof(TWsEvent)); sl@0: } sl@0: sl@0: TInt CEventQueue::RequiredQueueSize(TInt aNumConnections) sl@0: { sl@0: return(aNumConnections*EMinQueueSize+EMaxQueueSize+EExtraQueueSize); sl@0: } sl@0: sl@0: /** sl@0: Adjust the Global Queue Size. sl@0: @param aNewSize the size for event queue. sl@0: */ sl@0: void CEventQueue::AdjustQueueSizeL(TInt aNewSize) sl@0: { sl@0: TWsEvent* oldQ=iGlobalEventQueue; sl@0: if (aNewSize < iGlobalEventQueueSize) sl@0: { sl@0: // Re-alloc wont move the cell down to a lower address, this means once this cell is sl@0: // high up in memory it may never move down again, thus wasting loads of global heap space. sl@0: const CEventQueue* last=iQueueList.Last(); sl@0: if ((last->iEventPtr + last->iQueueSize) >= (iGlobalEventQueue + aNewSize)) sl@0: { sl@0: return; sl@0: } sl@0: TInt allocSize = aNewSize * sizeof(TWsEvent); sl@0: iGlobalEventQueue=static_cast(User::AllocL(allocSize)); sl@0: Mem::Copy(iGlobalEventQueue,oldQ,allocSize); sl@0: User::Free(oldQ); sl@0: } sl@0: else sl@0: { sl@0: iGlobalEventQueue = static_cast(User::ReAllocL(iGlobalEventQueue, aNewSize * sizeof(TWsEvent))); sl@0: } sl@0: __ZAP_EVENTS(iGlobalEventQueue + iGlobalEventQueueSize, aNewSize - iGlobalEventQueueSize); sl@0: iGlobalEventQueueSize = aNewSize; sl@0: // coverity[use_after_free] sl@0: TInt diff=(reinterpret_cast(iGlobalEventQueue)-reinterpret_cast(oldQ)); sl@0: if (diff) sl@0: { sl@0: TDblQueIter iter(iQueueList); sl@0: CEventQueue* qptr; sl@0: while((qptr=iter++)!=NULL) sl@0: { sl@0: qptr->iEventPtr=reinterpret_cast(reinterpret_cast(qptr->iEventPtr)+diff); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CEventQueue::AddQueueL() sl@0: { sl@0: Wait(); sl@0: if ((iNumConnections%EQueueGranularity)==0) sl@0: { sl@0: const TInt newSize = RequiredQueueSize(iNumConnections + EQueueGranularity); sl@0: TRAPD(err,AdjustQueueSizeL(newSize)); sl@0: if (err!=KErrNone) sl@0: { sl@0: __CHECK_QUEUE(); sl@0: Signal(); sl@0: User::Leave(err); sl@0: } sl@0: } sl@0: iNumConnections++; sl@0: if (iQueueList.IsEmpty()) sl@0: iEventPtr=iGlobalEventQueue; sl@0: else sl@0: { sl@0: CEventQueue* qptr=iQueueList.Last(); sl@0: iEventPtr=qptr->iEventPtr+qptr->iQueueSize; sl@0: } sl@0: iQueueList.AddLast(*this); sl@0: sl@0: //Initialize the queue size to at least EMinQueueSize sl@0: //Check the queue by doing standard queue compression. sl@0: TBool isExpanded = ETrue; sl@0: do {isExpanded = Expand(EEventPriorityLow);} while ((iQueueSize < EMinQueueSize) && isExpanded); sl@0: while (iQueueSize < EMinQueueSize) sl@0: { sl@0: //Cannot get enough spaces by doing standard queue compression, sl@0: //try to grow the global queue. sl@0: TInt sizeRequired = EMinQueueSize - iQueueSize; sl@0: const TInt newSize = iGlobalEventQueueSize + sizeRequired; sl@0: TRAPD(err, AdjustQueueSizeL(newSize)); sl@0: if (err != KErrNone) sl@0: { sl@0: //Cannot get enough spaces by growing global queue. sl@0: //try to purge the oldest events from inactive clients. sl@0: TInt numEventCleared = PurgeInactiveEvents(sizeRequired); sl@0: if (numEventCleared == 0) sl@0: { sl@0: __CHECK_QUEUE(); sl@0: Signal(); sl@0: User::Leave(err); sl@0: } sl@0: } sl@0: while (doExpand(ECompressNoPurge)) {}; sl@0: } sl@0: __CHECK_QUEUE(); sl@0: Signal(); sl@0: } sl@0: sl@0: void CEventQueue::RemoveQueue() sl@0: { sl@0: Wait(); sl@0: if (iEventPtr) // If this is still NULL this class hasn't been linked into the Q list sl@0: { sl@0: __ZAP_EVENTS(iEventPtr, iQueueSize); sl@0: iLink.Deque(); sl@0: if (--iNumConnections==0) sl@0: { sl@0: User::Free(iGlobalEventQueue); sl@0: iGlobalEventQueue=NULL; sl@0: iGlobalEventQueueSize=0; sl@0: } sl@0: else if ((iNumConnections%EQueueGranularity)==0) sl@0: { sl@0: TDblQueIter iter(iQueueList); sl@0: CEventQueue* qptr=iter++; sl@0: qptr->Compress(ECompressNoPurge); sl@0: while((qptr=iter++)!=NULL) sl@0: { sl@0: qptr->SqueezeDown(); sl@0: } sl@0: const TInt newSize = RequiredQueueSize(iNumConnections); sl@0: TRAP_IGNORE(AdjustQueueSizeL(newSize)); sl@0: // Can easily leave as we need to allocate the new smaller queue before freeing sl@0: // the old queue. But if it does it doesn't matter as we'll simply be left with sl@0: // a larger than necessary buffer until the next realloc sl@0: } sl@0: iCount=0; sl@0: } sl@0: __CHECK_QUEUE(); sl@0: Signal(); sl@0: } sl@0: sl@0: void CEventQueue::IncreaseQueueSize(TInt aNumSpaces) sl@0: { sl@0: if ((iQueueSize+aNumSpaces)>EMaxQueueSize) sl@0: aNumSpaces=EMaxQueueSize-iQueueSize; sl@0: EventCopy(iEventPtr+iHead+aNumSpaces, iEventPtr+iHead, iQueueSize-iHead); sl@0: __ZAP_EVENTS(iEventPtr+iHead, aNumSpaces); sl@0: iQueueSize+=aNumSpaces; sl@0: iHead=(iHead+aNumSpaces)%iQueueSize; sl@0: } sl@0: sl@0: TBool CEventQueue::Expand(TWservEventPriorities aPriority) sl@0: { sl@0: if (iQueueSize==EMaxQueueSize) sl@0: { sl@0: if (aPriority==EEventPriorityHigh) sl@0: { sl@0: Purge(); sl@0: if (iCount iter(iQueueList); sl@0: iter.SetToLast(); sl@0: CEventQueue* qptr=NULL; sl@0: TInt spare=0; sl@0: sl@0: // while loop from last queue till current queue, moving all queues up sl@0: // to get all the space from between them sl@0: while((qptr=iter)!=this) sl@0: { sl@0: spare=qptr->SqueezeUp(); sl@0: if (spare==0) sl@0: qptr->Compress(aCompressMode); sl@0: iter--; sl@0: } sl@0: sl@0: // current queue, if we have space then expand the same and return sl@0: spare=FollowingGap(); sl@0: if (spare>0) sl@0: { sl@0: IncreaseQueueSize(spare); sl@0: __CHECK_QUEUE(); sl@0: return(ETrue); sl@0: } sl@0: sl@0: // while loop from current queue till first queue, looking for a gap sl@0: // between queues and using the first one it finds sl@0: iter--; sl@0: TInt expanded=0; sl@0: while((qptr=iter)!=NULL) sl@0: { sl@0: expanded=qptr->SqueezeUp(); sl@0: if (expanded>0) sl@0: { sl@0: return MoveDownAndExpand(iter, expanded); sl@0: } sl@0: else sl@0: qptr->Compress(aCompressMode); sl@0: iter--; sl@0: } sl@0: sl@0: // Even by doing all the above if we did not find space then check if first sl@0: // queue has some space before it. If so then make use of it and movedown all the sl@0: // queue till the current queue and then use the space for expansion sl@0: iter.SetToFirst(); sl@0: qptr=iter; sl@0: if (qptr->iEventPtr>iGlobalEventQueue) sl@0: { sl@0: return MoveDownAndExpand(iter, qptr->iEventPtr-iGlobalEventQueue); sl@0: } sl@0: sl@0: __CHECK_QUEUE(); sl@0: return(EFalse); // Failed to expand enough room sl@0: } sl@0: sl@0: // This function moves the queue down by given amount and repeats this until sl@0: // the current queue and then expand the same sl@0: TBool CEventQueue::MoveDownAndExpand(TDblQueIter &aIter, TInt aExpand) sl@0: { sl@0: CEventQueue* qptr=NULL; sl@0: FOREVER sl@0: { sl@0: qptr=aIter++; sl@0: qptr->MoveDown(aExpand); sl@0: if (qptr==this) sl@0: { sl@0: IncreaseQueueSize(aExpand); sl@0: __CHECK_QUEUE(); sl@0: break; sl@0: } sl@0: } sl@0: return ETrue; sl@0: } sl@0: sl@0: void CEventQueue::MoveDown(TInt aMove) sl@0: { sl@0: if (!aMove) sl@0: { sl@0: return; sl@0: } sl@0: EventCopy(iEventPtr-aMove,iEventPtr,iQueueSize); sl@0: iEventPtr-=aMove; sl@0: } sl@0: sl@0: /*void CEventQueue::LogUpDownEvents(TChar aChar) sl@0: { sl@0: TWsEvent *event; sl@0: TBuf<128> buf; sl@0: buf.Zero(); sl@0: buf.Append(aChar); sl@0: buf.Append('#'); sl@0: buf.Append('#'); sl@0: TBool some=EFalse; sl@0: TInt index; sl@0: sl@0: for (index=0;indexType()==EEventPointer) sl@0: { sl@0: if (event->Pointer()->iType==TPointerEvent::EButton1Down sl@0: || event->Pointer()->iType==TPointerEvent::EButton1Up) sl@0: { sl@0: some=ETrue; sl@0: if (event->Pointer()->iType==TPointerEvent::EButton1Down) sl@0: buf.Append('D'); sl@0: else sl@0: buf.Append('U'); sl@0: buf.AppendNum(index); sl@0: } sl@0: } sl@0: } sl@0: if (wsDebugLog) sl@0: wsDebugLog->MiscMessage(ELogImportant,buf); sl@0: }*/ sl@0: sl@0: inline void CEventQueue::IncEventPointer(TWsEvent*& aEventPtr) sl@0: { sl@0: // iEventPtr[iQueueSize] is the element beyond the array, used for efficient bounds checking of the circular buffer only, do not access!! sl@0: if(++aEventPtr==&iEventPtr[iQueueSize]) sl@0: { sl@0: aEventPtr=iEventPtr; sl@0: } sl@0: } sl@0: sl@0: inline void CEventQueue::DecEventPointer(TWsEvent*& aEventPtr) sl@0: { sl@0: if(aEventPtr--==iEventPtr) sl@0: { sl@0: aEventPtr=&iEventPtr[iQueueSize - 1]; sl@0: } sl@0: } sl@0: sl@0: /* sl@0: Starting from aEventToPurge searches the queue for matching event by iterating towards end of queue. sl@0: Matching event will be a pointer event with the same window handle and pointer number sl@0: as aEventToPurge, but will have type aMatchingType. If matching event is found, it will sl@0: be removed from the queue and search will finish. sl@0: sl@0: Search will be stopped if an event of type aSearchTerminator is found with the same pointer number sl@0: as aEventToPurge. sl@0: sl@0: If search is not stopped by aSearchTerminator and matching event is not found, TWsPointer sl@0: class is notified that matching event has not been removed, so if it arrives in the future, sl@0: TWsPointer class will be able to ignore it. sl@0: */ sl@0: void CEventQueue::PurgeEventPairs(TWsEvent* aEventToPurge, TPointerEvent::TType aMatchingType, TPointerEvent::TType aSearchTerminator) sl@0: { sl@0: TWsEvent* eventToMatch = aEventToPurge; sl@0: TWsEvent* lastEvent = EventPtr(iCount); sl@0: for(IncEventPointer(eventToMatch);eventToMatch!=lastEvent;IncEventPointer(eventToMatch)) sl@0: { sl@0: if ( (eventToMatch->Type()==EEventPointer) // Must be checked first to ensure it is pointer data checked later sl@0: && (TAdvancedPointerEventHelper::PointerNumber(*eventToMatch) == TAdvancedPointerEventHelper::PointerNumber(*aEventToPurge))) // same pointer sl@0: { sl@0: if ((eventToMatch->Pointer()->iType==aMatchingType) // correct event type sl@0: && (eventToMatch->Handle()==aEventToPurge->Handle())) // same window sl@0: { sl@0: *eventToMatch=iNullEvent; sl@0: return; sl@0: } sl@0: else if (eventToMatch->Pointer()->iType==aSearchTerminator) // stop searching for mathing type sl@0: { sl@0: return; sl@0: } sl@0: } sl@0: }; sl@0: TWsPointer::UnmatchedEventPurged(aMatchingType, aEventToPurge); sl@0: } sl@0: sl@0: /** sl@0: Starting from pointer event aBasePointerEvent searches the queue for next pointer event for sl@0: the same pointer by iterating towards end of queue. sl@0: sl@0: @param aBasePointerEvent must be of type EEventPointer sl@0: @return Next pointer event in the queue for the same pointer as aBasePointerEvent sl@0: if it has the same handle as aBasePointerEvent or NULL if it has different handle. sl@0: NULL if there is no next pointer event for the same pointer in the queue. sl@0: */ sl@0: TWsEvent* CEventQueue::NextPointerEvent(TWsEvent* aBasePointerEvent) sl@0: { sl@0: WS_ASSERT_DEBUG(aBasePointerEvent->Type() == EEventPointer, EWsPanicCheckEventQueue); sl@0: TWsEvent* currentEvent = aBasePointerEvent; sl@0: TWsEvent* lastEvent = EventPtr(iCount); sl@0: TUint8 pointerNumber = TAdvancedPointerEventHelper::PointerNumber(*aBasePointerEvent); sl@0: TUint handle = aBasePointerEvent->Handle(); sl@0: for(IncEventPointer(currentEvent);currentEvent!=lastEvent;IncEventPointer(currentEvent)) sl@0: { sl@0: if ((currentEvent->Type() == EEventPointer) && sl@0: (TAdvancedPointerEventHelper::PointerNumber(*currentEvent) == pointerNumber)) sl@0: { sl@0: if (currentEvent->Handle() == handle) sl@0: { sl@0: return currentEvent; sl@0: } sl@0: else sl@0: { sl@0: return NULL; sl@0: } sl@0: } sl@0: }; sl@0: return NULL; sl@0: } sl@0: sl@0: /** sl@0: Checks if aEventToPurge should be purged. If it can be purged, then events that should sl@0: be purged together with aEventToPurge (matching events) are overwritten with iNullEvent. sl@0: sl@0: @return ETrue if aEventToPurge should be purged, EFalse otherwise. sl@0: */ sl@0: TBool CEventQueue::CheckPurgePointerEvent(TWsEvent* aEventToPurge) sl@0: { sl@0: switch(aEventToPurge->Pointer()->iType) sl@0: { sl@0: case TPointerEvent::EDrag: sl@0: case TPointerEvent::EMove: sl@0: case TPointerEvent::EButtonRepeat: sl@0: case TPointerEvent::ESwitchOn: sl@0: return ETrue; sl@0: case TPointerEvent::EButton1Down: sl@0: PurgeEventPairs(aEventToPurge,TPointerEvent::EButton1Up, TPointerEvent::ENullType); sl@0: return ETrue; sl@0: case TPointerEvent::EButton2Down: sl@0: PurgeEventPairs(aEventToPurge,TPointerEvent::EButton2Up, TPointerEvent::ENullType); sl@0: return ETrue; sl@0: case TPointerEvent::EButton3Down: sl@0: PurgeEventPairs(aEventToPurge,TPointerEvent::EButton3Up, TPointerEvent::ENullType); sl@0: return ETrue; sl@0: case TPointerEvent::EEnterHighPressure: sl@0: PurgeEventPairs(aEventToPurge,TPointerEvent::EExitHighPressure, TPointerEvent::EButton1Up); sl@0: return ETrue; sl@0: case TPointerEvent::EEnterCloseProximity: sl@0: { sl@0: TWsEvent* nextEvent = NextPointerEvent(aEventToPurge); sl@0: if (nextEvent != NULL) sl@0: { sl@0: switch(nextEvent->Pointer()->iType) sl@0: { sl@0: case TPointerEvent::EExitCloseProximity: sl@0: *nextEvent = iNullEvent; sl@0: case TPointerEvent::EOutOfRange: sl@0: return ETrue; sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: case TPointerEvent::EExitCloseProximity: sl@0: { sl@0: TWsEvent* nextEvent = NextPointerEvent(aEventToPurge); sl@0: if (nextEvent != NULL) sl@0: { sl@0: switch(nextEvent->Pointer()->iType) sl@0: { sl@0: case TPointerEvent::EEnterCloseProximity: sl@0: *nextEvent = iNullEvent; sl@0: case TPointerEvent::EOutOfRange: sl@0: return ETrue; sl@0: } sl@0: } sl@0: break; sl@0: } sl@0: case TPointerEvent::EOutOfRange: sl@0: { sl@0: TWsEvent* nextEvent = NextPointerEvent(aEventToPurge); sl@0: if ((nextEvent != NULL) && sl@0: (nextEvent->Pointer()->iType == TPointerEvent::EOutOfRange)) sl@0: { sl@0: return ETrue; sl@0: } sl@0: break; sl@0: } sl@0: case TPointerEvent::EExitHighPressure: sl@0: { sl@0: TWsEvent* nextEvent = NextPointerEvent(aEventToPurge); sl@0: if ((nextEvent != NULL) && sl@0: (nextEvent->Pointer()->iType == TPointerEvent::EButton1Up)) sl@0: { sl@0: return ETrue; sl@0: } sl@0: break; sl@0: } sl@0: case TPointerEvent::EButton1Up: sl@0: case TPointerEvent::EButton2Up: sl@0: case TPointerEvent::EButton3Up: sl@0: break; sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: /** Purgable events are: sl@0: Pointer Up/Down pairs belonging to the same pointer, button and window sl@0: Pointer moves & drags sl@0: Key messages sl@0: Key Up/Down pairs sl@0: Key Ups if not foreground connection sl@0: Focus lost/gained pairs sl@0: EEnterHighPressure/EExitHighPressure pairs belonging to the same pointer sl@0: EEnterCloseProximity/EExitCloseProximity pairs belonging to the same pointer sl@0: Lone EEnterHighPressure, EExitHighPressure if followed by Up for the same pointer sl@0: Lone EEnterCloseProximity, EExitCloseProximity if followed by EOutOfRange for the same pointer sl@0: EOutOfRange if followed by another EOutOfRange for the same pointer sl@0: sl@0: Events that must not be purged: sl@0: Key ups for foreground connections queue sl@0: Lone pointer ups, must be delivered to match preceeding pointer down sl@0: Lone EExitHighPressure if not followed by Up, must be delivered to match preceeding EEnterHighPressure sl@0: Lone EEnterCloseProximity, EExitCloseProximity not followed by EOutOfRange for the same pointer sl@0: Lone focus lost/gained messages sl@0: */ sl@0: void CEventQueue::Purge() sl@0: { sl@0: TWsEvent* eventToPurge; sl@0: TWsEvent* eventToMatch; sl@0: TInt indexToMatch; sl@0: TInt indexToPurge=iCount; sl@0: while(indexToPurge>0) sl@0: { sl@0: eventToPurge=EventPtr(--indexToPurge); sl@0: switch(eventToPurge->Type()) sl@0: { sl@0: case EEventPassword: sl@0: break; sl@0: case EEventMarkInvalid: sl@0: #if defined(_DEBUG) sl@0: WS_PANIC_DEBUG(EWsPanicCheckEventQueue); sl@0: #endif sl@0: case EEventNull: sl@0: case EEventKey: sl@0: case EEventPointerEnter: sl@0: case EEventPointerExit: sl@0: case EEventDragDrop: sl@0: breakLoopAndRemoveEvent: sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Print(_L("_WSEVENT: CEventQueue::Purge(), The event to be purged is %S"), &WsEventName(*eventToPurge)); sl@0: #endif sl@0: RemoveEvent(indexToPurge); sl@0: return; sl@0: case EEventKeyUp: sl@0: if (iQueueList.First()!=this) sl@0: goto breakLoopAndRemoveEvent; sl@0: break; sl@0: case EEventKeyDown: sl@0: if (iQueueList.First()!=this) sl@0: goto breakLoopAndRemoveEvent; sl@0: for (indexToMatch=indexToPurge+1;indexToMatchType()==EEventKeyUp && eventToMatch->Key()->iScanCode==eventToPurge->Key()->iScanCode) sl@0: { sl@0: *eventToMatch=iNullEvent; sl@0: goto breakLoopAndRemoveEvent; sl@0: } sl@0: } sl@0: break; sl@0: case EEventModifiersChanged: sl@0: for (indexToMatch=indexToPurge;indexToMatch>0;) sl@0: { sl@0: eventToMatch=EventPtr(--indexToMatch); sl@0: if (eventToMatch->Type()==EEventModifiersChanged) sl@0: { sl@0: eventToPurge->ModifiersChanged()->iChangedModifiers|=eventToMatch->ModifiersChanged()->iChangedModifiers; sl@0: indexToPurge=indexToMatch; sl@0: goto breakLoopAndRemoveEvent; sl@0: } sl@0: } sl@0: break; sl@0: case EEventPointerBufferReady: sl@0: CWsPointerBuffer::DiscardPointerMoveBuffer(eventToPurge->Handle()); sl@0: goto breakLoopAndRemoveEvent; sl@0: case EEventFocusLost: sl@0: case EEventFocusGained: sl@0: if ((indexToPurge+1)Type()==EEventFocusLost || eventToMatch->Type()==EEventFocusGained) sl@0: { sl@0: *eventToMatch=iNullEvent; sl@0: goto breakLoopAndRemoveEvent; sl@0: } sl@0: } sl@0: break; sl@0: case EEventSwitchOn: sl@0: if ((indexToPurge+1)Type()==EEventSwitchOn) sl@0: goto breakLoopAndRemoveEvent; sl@0: break; sl@0: case EEventPointer: sl@0: if (CheckPurgePointerEvent(eventToPurge)) sl@0: { sl@0: goto breakLoopAndRemoveEvent; sl@0: } sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CEventQueue::PurgePointerEvents() sl@0: { sl@0: TWsEvent* eventToPurge; sl@0: TInt indexToPurge=iCount; sl@0: while(indexToPurge>0) sl@0: { sl@0: eventToPurge=EventPtr(--indexToPurge); sl@0: switch(eventToPurge->Type()) sl@0: { sl@0: case EEventPointerBufferReady: sl@0: CWsPointerBuffer::DiscardPointerMoveBuffer(eventToPurge->Handle()); sl@0: RemoveEvent(indexToPurge); sl@0: break; sl@0: case EEventPointer: sl@0: if (CheckPurgePointerEvent(eventToPurge)) sl@0: { sl@0: RemoveEvent(indexToPurge); sl@0: } sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Purge requested number of oldest events from inactive event queue. sl@0: @param aSizeRequired the total events required to be cleared. sl@0: @return The number of events cleared. sl@0: */ sl@0: TInt CEventQueue::PurgeInactiveEvents(const TInt& aSizeRequired) sl@0: { sl@0: TInt numEventsCleared = 0; sl@0: CEventQueue* qptr; sl@0: TBool isRemoved; sl@0: do { sl@0: TDblQueIter iter(iQueueList); sl@0: isRemoved = EFalse; sl@0: while ((qptr = iter++) != NULL && (aSizeRequired > numEventsCleared)) sl@0: { sl@0: if ((qptr->IsEventCancelled() || (qptr->iEventMsg.IsNull() && !qptr->iEventSignalledState)) && sl@0: (qptr->iQueueSize > EMinQueueSize)) sl@0: { sl@0: // we have a client that is not listening with a size larger than min queue size. sl@0: // so lets remove it's oldest event until the number of removed events meet the requirement. sl@0: qptr->RemoveEvent(0); sl@0: numEventsCleared++; sl@0: isRemoved = ETrue; sl@0: } sl@0: } sl@0: } while ((aSizeRequired > numEventsCleared) && isRemoved); sl@0: return numEventsCleared; sl@0: } sl@0: sl@0: void CEventQueue::Compress(TCompressMode aCompressMode) sl@0: { sl@0: // sl@0: // The different purge modes are sl@0: // sl@0: // ECompressNoPurge, // Don't purge anything sl@0: // ECompressPurge1, // Don't purge foreground queue sl@0: // ECompressPurge2, // Purge all queues sl@0: // sl@0: if (aCompressMode==ECompressPurge2 || sl@0: (this!=iQueueList.First() && aCompressMode==ECompressPurge1)) sl@0: Purge(); sl@0: TInt compress=iQueueSize-(iCount>EMinQueueSize?iCount:EMinQueueSize); sl@0: if (compress>0) sl@0: { sl@0: compress=(compress+1)/2; // Compress half the free space in the queue sl@0: TWsEvent* head=EventPtr(0); sl@0: TWsEvent* tail=EventPtr(iCount); sl@0: if (head>tail) sl@0: { sl@0: EventCopy(iEventPtr+compress,iEventPtr,tail-iEventPtr); sl@0: iHead-=compress; sl@0: } sl@0: else sl@0: { sl@0: EventCopy(iEventPtr+compress,head,iCount); sl@0: iHead=0; sl@0: } sl@0: iEventPtr+=compress; sl@0: iQueueSize-=compress; sl@0: } sl@0: } sl@0: sl@0: void CEventQueue::MoveUp(TInt aNumEvents) sl@0: { sl@0: if (!aNumEvents) sl@0: { sl@0: return; sl@0: } sl@0: EventCopy(iEventPtr+aNumEvents,iEventPtr,iQueueSize); sl@0: iEventPtr+=aNumEvents; sl@0: } sl@0: sl@0: TInt CEventQueue::FollowingGap() const sl@0: { sl@0: TDblQueIter iter(iQueueList); sl@0: CEventQueue* qptr; sl@0: iter.Set(*(CEventQueue *)this); sl@0: iter++; sl@0: TWsEvent* end; sl@0: if ((qptr=iter)!=NULL) sl@0: end=qptr->iEventPtr; sl@0: else sl@0: end=iGlobalEventQueue+iGlobalEventQueueSize; sl@0: return(end-(iEventPtr+iQueueSize)); sl@0: } sl@0: sl@0: TInt CEventQueue::SqueezeUp() sl@0: { sl@0: TInt gap=FollowingGap(); sl@0: MoveUp(gap); sl@0: return(gap); sl@0: } sl@0: sl@0: void CEventQueue::SqueezeDown() sl@0: { sl@0: TDblQueIter iter(iQueueList); sl@0: iter.Set(*this); sl@0: iter--; sl@0: CEventQueue* qptr=iter; sl@0: if (qptr!=NULL) sl@0: { sl@0: Compress(ECompressNoPurge); sl@0: TInt gap=qptr->FollowingGap(); sl@0: MoveDown(gap); sl@0: } sl@0: } sl@0: sl@0: void CEventQueue::MoveToFront() sl@0: { sl@0: if (this==iQueueList.First()) sl@0: return; sl@0: Wait(); sl@0: CEventQueue* qptr; sl@0: TInt gap=0; sl@0: TDblQueIter iter(iQueueList); sl@0: iter.SetToLast(); sl@0: while((qptr=iter--)!=NULL) sl@0: { sl@0: if (gapCompress(ECompressNoPurge); sl@0: gap=qptr->SqueezeUp(); sl@0: } sl@0: if (gap>=iQueueSize) sl@0: EventCopy(iGlobalEventQueue,iEventPtr,iQueueSize); sl@0: else sl@0: { sl@0: EventCopy(iGlobalEventQueue,iEventPtr,gap); sl@0: iEventPtr+=gap; sl@0: TWsEvent copyBuf[ECopyBufSize]; // temp buffer, can copy upto ECopyBufSize events at a time sl@0: TInt eventsToGo=iQueueSize-gap; sl@0: iQueueSize=gap; sl@0: do sl@0: { sl@0: TInt copy=Min(eventsToGo,ECopyBufSize); sl@0: Mem::Copy(©Buf[0],iEventPtr,copy*sizeof(TWsEvent)); sl@0: iter.Set(*this); sl@0: iter--; sl@0: while((qptr=iter--)!=NULL) sl@0: qptr->MoveUp(copy); sl@0: EventCopy(iGlobalEventQueue+iQueueSize,©Buf[0],copy); sl@0: iQueueSize+=copy; sl@0: eventsToGo-=copy; sl@0: iEventPtr+=copy; sl@0: } while(eventsToGo>0); sl@0: } sl@0: iEventPtr=iGlobalEventQueue; sl@0: this->iLink.Deque(); sl@0: iQueueList.AddFirst(*this); sl@0: __CHECK_QUEUE(); sl@0: Signal(); sl@0: } sl@0: sl@0: // CEventQueue sl@0: sl@0: CEventQueue::CEventQueue(CWsClient* aOwner) : CEventBase(aOwner) sl@0: { sl@0: __DECLARE_NAME(_S("CEventQueue")); sl@0: } sl@0: sl@0: CEventQueue::~CEventQueue() sl@0: { sl@0: RemoveQueue(); sl@0: } sl@0: sl@0: void CEventQueue::InitStaticsL() sl@0: { sl@0: User::LeaveIfError(iMutex.CreateLocal()); sl@0: } sl@0: sl@0: void CEventQueue::DeleteStaticsL() sl@0: { sl@0: iMutex.Close(); sl@0: } sl@0: sl@0: void CEventQueue::ConstructL() sl@0: { sl@0: AddQueueL(); sl@0: Mem::FillZ(&iNullEvent,sizeof(iNullEvent)); sl@0: } sl@0: sl@0: TWsEvent* CEventQueue::EventPtr(TInt index) sl@0: { sl@0: return(iEventPtr+((iHead+index)%iQueueSize)); sl@0: } sl@0: sl@0: TBool CEventQueue::QueueEvent(const TWsEvent &event) sl@0: { sl@0: TWservEventPriorities priority=EEventPriorityLow; sl@0: #ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP sl@0: if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || sl@0: event.Type()==EEventKeySwitchOff || event.Type()==EEventRestartSystem) sl@0: #else sl@0: if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || event.Type()==EEventKeySwitchOff) sl@0: #endif sl@0: { sl@0: priority=EEventPriorityHigh; sl@0: } sl@0: return(QueueEvent(event,priority)); sl@0: } sl@0: sl@0: TBool CEventQueue::CheckRoom() sl@0: // sl@0: // If the queue is full and room is created return ETrue sl@0: // sl@0: { sl@0: TBool ret=EFalse; sl@0: Wait(); sl@0: if (iCount==iQueueSize && Expand(EEventPriorityHigh)) sl@0: ret=ETrue; sl@0: Signal(); sl@0: return(ret); sl@0: } sl@0: sl@0: TBool CEventQueue::QueueEvent(const TWsEvent &event, TWservEventPriorities aPriority) sl@0: // sl@0: // Queue an event, returns ETrue if queued or delivered, EFalse if the queue was full. sl@0: // sl@0: { sl@0: TBool ret=ETrue; sl@0: Wait(); sl@0: if (iCount==iQueueSize && !Expand(aPriority)) sl@0: { sl@0: ret=EFalse; sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Printf("WSEVENT: CEventQueue::QueueEvent(): 0x%X:  Queue Full!!!!!, iCount = %d, iQueueSize = %d", this, iCount, iQueueSize); sl@0: RDebug::Print(_L("WSEVENT: CEventQueue::QueueEvent(): 0x%X:  Queue Full!!!!! TWsEvent.Type() = %S"), this, &WsEventName(event)); sl@0: #endif sl@0: } sl@0: else sl@0: { sl@0: if (!iEventMsg.IsNull()) sl@0: { sl@0: SignalEvent(); sl@0: } sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Printf("_WSEVENT: CEventQueue::QueueEvent, Right before adding the event"); sl@0: #endif sl@0: *EventPtr(iCount++)=event; sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Print(_L("_WSEVENT: CEventQueue::QueueEvent, Event %S successfully queued"), &WsEventName(event)); sl@0: #endif sl@0: } sl@0: Signal(); sl@0: return(ret); sl@0: } sl@0: sl@0: TBool CEventQueue::QueueEvent(TUint32 aTarget, TInt aEvent, TInt aIntVal) sl@0: { sl@0: TWsEvent event; sl@0: event.SetType(aEvent); sl@0: event.SetHandle(aTarget); sl@0: event.SetTimeNow(); sl@0: *(event.Int()) = aIntVal; sl@0: return(QueueEvent(event)); sl@0: } sl@0: sl@0: void CEventQueue::UpdateLastEvent(const TWsEvent &event) sl@0: { sl@0: WS_ASSERT_DEBUG(iCount>0, EWsPanicQueueUpdateCount); sl@0: Mem::Copy(EventPtr(iCount-1)->EventData(),event.EventData(),TWsEvent::EWsEventDataSize); sl@0: } sl@0: sl@0: /* sl@0: Replaces last pointer event related to particular pointer with new one. sl@0: sl@0: While searching for event to replace this method considers all events on the sl@0: queue except EMove and EDrag pointer events from pointers different than aEvent. sl@0: If the last of these events under consideration: sl@0: (1) is a pointer event, sl@0: (2) has the same type as aEvent, sl@0: (3) its type is either EMove or EDrag and sl@0: (4) has the same window handle as aEvent, sl@0: then it is removed from the queue and aEvent is put at the end of the queue. sl@0: sl@0: @return ETrue if event on the queue has been replaced with aEvent, EFalse otherwise. sl@0: */ sl@0: TBool CEventQueue::UpdateLastPointerEvent(const TWsEvent &aEvent) sl@0: { sl@0: if (aEvent.Pointer()->iType == TPointerEvent::EMove || aEvent.Pointer()->iType == TPointerEvent::EDrag) sl@0: { sl@0: Wait(); sl@0: sl@0: if (iCount == 0) sl@0: { sl@0: Signal(); sl@0: return EFalse; sl@0: } sl@0: sl@0: // loop through all events on the queue starting from the last one sl@0: TWsEvent* evToUpdate = EventPtr(iCount); sl@0: TWsEvent* evOnHead = &iEventPtr[iHead]; sl@0: while (evToUpdate != evOnHead) sl@0: { sl@0: DecEventPointer(evToUpdate); sl@0: sl@0: // conditions that stop searching sl@0: if ( (evToUpdate->Type() != EEventPointer) // found non-pointer event sl@0: || (evToUpdate->Pointer()->iType != TPointerEvent::EMove && evToUpdate->Pointer()->iType != TPointerEvent::EDrag) // pointer event but wrong type sl@0: || ( (TAdvancedPointerEventHelper::PointerNumber(*evToUpdate) == TAdvancedPointerEventHelper::PointerNumber(aEvent)) sl@0: && ( (evToUpdate->Handle() != aEvent.Handle()) // good number & bad handle sl@0: || (evToUpdate->Pointer()->iType != aEvent.Pointer()->iType)))) // good number & bad type sl@0: { sl@0: Signal(); sl@0: return EFalse; sl@0: } sl@0: else if (TAdvancedPointerEventHelper::PointerNumber(*evToUpdate) == TAdvancedPointerEventHelper::PointerNumber(aEvent)) sl@0: { sl@0: // we found event to update: evToUpdate is pointer event with right type, pointer number sl@0: // and window handle sl@0: sl@0: if (evToUpdate == EventPtr(iCount - 1)) sl@0: { sl@0: UpdateLastEvent(aEvent); sl@0: } sl@0: else sl@0: { sl@0: RemoveEvent(evToUpdate); sl@0: *EventPtr(iCount++) = aEvent; sl@0: } sl@0: Signal(); sl@0: return ETrue; sl@0: } sl@0: sl@0: // evToUpdate is EMove or EDrag pointer event with different pointer id, sl@0: // continue to loop through the queue sl@0: } sl@0: Signal(); sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: void CEventQueue::GetData() sl@0: // sl@0: // If there is an outstanding event in the queue, reply with it's data and remove it from the Q sl@0: // sl@0: { sl@0: if (iCount>0) sl@0: { sl@0: WS_ASSERT_DEBUG((iEventPtr+iHead)->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue); sl@0: CEventBase::GetData(iEventPtr+iHead,sizeof(*iEventPtr)); sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Printf("_WSEVENT: CEventQueue::GetData(), TWsEvent.Type() = %d", (iEventPtr+iHead)->Type()); sl@0: #endif sl@0: __ZAP_EVENT(iEventPtr+iHead); sl@0: iHead=(iHead+1)%iQueueSize; sl@0: iCount--; sl@0: } sl@0: else sl@0: CEventBase::GetData(&iNullEvent,sizeof(iNullEvent)); sl@0: } sl@0: sl@0: void CEventQueue::EventReady(const RMessagePtr2& aEventMsg) sl@0: // sl@0: // Queue a read of an event notification sl@0: // sl@0: { sl@0: EventReadyCheck(); sl@0: Wait(); sl@0: iEventMsg=aEventMsg; sl@0: if (iCount>0) sl@0: SignalEvent(); sl@0: Signal(); sl@0: } sl@0: sl@0: void CEventQueue::RemoveEvent(TInt index) sl@0: // sl@0: // Remove event 'index' in the queue, this event MUST exist in the queue sl@0: // sl@0: { sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Printf("_WSEVENT: CEventQueue::RemoveEvent(index), Remove event index %d in the queue", index); sl@0: #endif sl@0: WS_ASSERT_DEBUG(index < iCount, EWsPanicCheckEventQueue); sl@0: RemoveEvent(EventPtr(index)); sl@0: } sl@0: sl@0: void CEventQueue::RemoveEvent(TWsEvent* aEvToRemove) sl@0: // sl@0: // Remove event in the queue, this event MUST exist in the queue sl@0: // sl@0: { sl@0: #ifdef LOG_WSERV_EVENTS sl@0: RDebug::Print(_L("_WSEVENT: CEventQueue::RemoveEvent(aEvToRemove), Remove event %S in the queue"), &WsEventName(*aEvToRemove)); sl@0: #endif sl@0: iCount--; sl@0: TWsEvent* last = EventPtr(iCount); sl@0: TWsEvent* prev; sl@0: while(aEvToRemove!=last) sl@0: { sl@0: prev = aEvToRemove; sl@0: IncEventPointer(aEvToRemove); sl@0: *prev = *aEvToRemove; sl@0: } sl@0: __ZAP_EVENT(last); sl@0: } sl@0: sl@0: const TWsEvent* CEventQueue::PeekLastEvent() sl@0: // sl@0: // Return a read only pointer to the last event in the queue (or NULL if no event) sl@0: // sl@0: { sl@0: if (iCount==0) sl@0: return(NULL); sl@0: return(EventPtr(iCount-1)); sl@0: } sl@0: sl@0: void CEventQueue::Wait() sl@0: { sl@0: iMutex.Wait(); sl@0: } sl@0: sl@0: void CEventQueue::Signal() sl@0: { sl@0: iMutex.Signal(); sl@0: } sl@0: sl@0: void CEventQueue::WalkEventQueue(EventQueueWalk aFunc, TAny* aFuncParam) sl@0: { sl@0: Wait(); sl@0: restart: sl@0: for (TInt index=0;index