sl@0: // Copyright (c) 1999-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: // Sprite sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include "sprite.h" sl@0: #include "rootwin.h" sl@0: #include "windowgroup.h" sl@0: #include "ScrDev.H" sl@0: #include "wstop.h" sl@0: #include "ANIM.H" sl@0: #include "offscreenbitmap.h" sl@0: #include "panics.h" sl@0: #include "EVENT.H" sl@0: sl@0: static const TInt64 KFlashHalfSecond(500000); //interval for flashing sprites sl@0: sl@0: GLDEF_D CWsDeltaTimer *CWsSpriteBase::iDeltaTimer=NULL; sl@0: sl@0: TInt TimerCallBack(TAny *aPtr) sl@0: { sl@0: ((CWsSpriteBase *)aPtr)->TimerExpired(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: // sl@0: // CWsSpriteMember sl@0: // sl@0: sl@0: CWsSpriteMember::CWsSpriteMember() sl@0: { sl@0: } sl@0: sl@0: CWsSpriteMember::~CWsSpriteMember() sl@0: { sl@0: delete iBitmap; sl@0: delete iMaskBitmap; sl@0: } sl@0: sl@0: TBool CWsSpriteMember::SetL(const TCmdSpriteMember &aCmdSpriteMember) sl@0: { sl@0: if (aCmdSpriteMember.iBitmap!=0) // Null member of sequence, time is only valid field in member data sl@0: { sl@0: iBitmap=new(ELeave) CFbsBitmap(); sl@0: TInt ret = iBitmap->Duplicate(aCmdSpriteMember.iBitmap); sl@0: if (ret == KErrNoMemory) sl@0: { sl@0: User::Leave(ret); sl@0: } sl@0: if (ret != KErrNone) sl@0: return(ETrue); sl@0: sl@0: if (aCmdSpriteMember.iMaskBitmap) sl@0: { sl@0: iMaskBitmap=new(ELeave) CFbsBitmap(); sl@0: TInt ret = iMaskBitmap->Duplicate(aCmdSpriteMember.iMaskBitmap); sl@0: if (ret == KErrNoMemory) sl@0: { sl@0: User::Leave(ret); sl@0: } sl@0: if (ret != KErrNone) sl@0: return(ETrue); sl@0: } sl@0: iInvertMask=aCmdSpriteMember.iInvertMask; sl@0: iDrawMode=aCmdSpriteMember.iDrawMode; sl@0: iOffset=aCmdSpriteMember.iOffset; sl@0: } sl@0: iInterval=aCmdSpriteMember.iInterval; sl@0: return(EFalse); sl@0: } sl@0: sl@0: // sl@0: // CWsSpriteBase sl@0: // sl@0: sl@0: TBool CWsSpriteBase::UpdateMemberL(CWsSpriteMember *aMember, const TCmdSpriteMember &aCmdSpriteMember) sl@0: { sl@0: CFbsBitmap *old=aMember->iBitmap; sl@0: CFbsBitmap *oldMask=aMember->iMaskBitmap; sl@0: aMember->iBitmap=NULL; sl@0: aMember->iMaskBitmap=NULL; sl@0: TBool ret=EFalse; sl@0: TRAPD(err,ret=aMember->SetL(aCmdSpriteMember)); sl@0: if (err!=KErrNone) sl@0: { sl@0: um_error: sl@0: delete aMember->iBitmap; sl@0: delete aMember->iMaskBitmap; sl@0: aMember->iBitmap=old; sl@0: aMember->iMaskBitmap=oldMask; sl@0: User::Leave(err); sl@0: } sl@0: TRAP(err,CheckSizesL()); sl@0: if (err!=KErrNone) sl@0: goto um_error; sl@0: SetMember(0); sl@0: delete old; sl@0: delete oldMask; sl@0: return(ret); sl@0: } sl@0: sl@0: void CWsSpriteBase::InitStaticsL() sl@0: { sl@0: iDeltaTimer=CWsDeltaTimer::NewL(ESpriteAnimatePriority); sl@0: } sl@0: sl@0: void CWsSpriteBase::DeleteStatics() sl@0: { sl@0: delete iDeltaTimer; sl@0: } sl@0: sl@0: CWsSpriteBase::CWsSpriteBase(CWsClient *owner, WH_HANDLES aType) : CWsScreenObject(owner,aType,owner->Screen()), iClipSprite(EFalse) sl@0: { sl@0: } sl@0: sl@0: CWsSpriteBase::~CWsSpriteBase() sl@0: { sl@0: Deactivate(); sl@0: sl@0: //iDeltaTimer->Remove(iDeltaTimerEntry); sl@0: if (iMembers) sl@0: { sl@0: iMembers->ResetAndDestroy(); sl@0: delete iMembers; sl@0: } sl@0: } sl@0: sl@0: void CWsSpriteBase::ForceRedraw() sl@0: { sl@0: TRegionFix<1> region; sl@0: region.AddRect(Rect()); sl@0: Screen()->AddRedrawRegion(region); sl@0: } sl@0: sl@0: void CWsSpriteBase::Deactivate() sl@0: { sl@0: //Disconnect from the sprite list and hide the sprite sl@0: if (iFlags & ESpriteActive) sl@0: { sl@0: if(iWin) sl@0: iWin->RemoveSprite(this); sl@0: if (iMembers && iMembers->Count()>1) sl@0: iDeltaTimer->Remove(iDeltaTimerEntry); sl@0: iFlags&=~ESpriteActive; sl@0: if (iFloating) sl@0: { sl@0: Screen()->SpriteManager()->RemoveFloatingSprite(this); sl@0: ForceRedraw(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CWsSpriteBase::CheckSizesL() sl@0: { sl@0: iMaxSize.SetSize(0,0); sl@0: for(TInt index=0;indexCount();index++) sl@0: { sl@0: CWsSpriteMember *wsm=(*iMembers)[index]; sl@0: if (wsm->iBitmap) sl@0: { sl@0: TSize size=wsm->iBitmap->SizeInPixels(); sl@0: if (wsm->iMaskBitmap) sl@0: { sl@0: TSize maskSize=wsm->iMaskBitmap->SizeInPixels(); sl@0: if (maskSize.iWidthiMaxSize.iWidth) sl@0: iMaxSize.iWidth=size.iWidth; sl@0: if (size.iHeight>iMaxSize.iHeight) sl@0: iMaxSize.iHeight=size.iHeight; sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CWsSpriteBase::ConstructL(TUint aFlags, CWsWindow *aWindow) sl@0: { sl@0: // Common part of construct for both sprites and pointer cursors sl@0: iFlags=aFlags; sl@0: /* sl@0: if (iFlags&ESpriteNoChildClip) sl@0: iLink.iPriority+=ENoChildPriorityBoost; sl@0: if (iFlags&ESpritePointer) sl@0: iLink.iPriority+=EPointerPriorityBoost; sl@0: */ sl@0: iWin=aWindow; sl@0: TCallBack callback(TimerCallBack,this); sl@0: iDeltaTimerEntry.Set(callback); sl@0: iMembers=new(ELeave) CArrayPtrFlat(10); sl@0: } sl@0: sl@0: void CWsSpriteBase::AppendMemberL(const TCmdSpriteMember &aCmdSpriteMember) sl@0: { sl@0: CWsSpriteMember *&pwsm=iMembers->ExtendL(); sl@0: pwsm=NULL; // In case new leaves sl@0: pwsm=new(ELeave) CWsSpriteMember(); sl@0: if (pwsm->SetL(aCmdSpriteMember)) sl@0: OwnerPanic(EWservPanicBitmap); sl@0: } sl@0: sl@0: void CWsSpriteBase::CompleteL() sl@0: { sl@0: if (iMembers->Count() <= 0) sl@0: { sl@0: if(iWin) sl@0: iWin->OwnerPanic(EWservPanicNoSpriteMember); sl@0: //Not sure if this is a neccessary fall back if iWin is NULL. sl@0: else if(iWin==NULL && iGroupWin) sl@0: iGroupWin->OwnerPanic(EWservPanicNoSpriteMember); sl@0: } sl@0: else sl@0: { sl@0: iMembers->Compress(); sl@0: CheckSizesL(); sl@0: SetMember(0); sl@0: } sl@0: } sl@0: sl@0: void CWsSpriteBase::Activate() sl@0: { sl@0: if (iFlags&ESpriteDisabled) sl@0: { sl@0: iFlags&=~ESpriteDisabled; sl@0: } sl@0: if (iMembers->Count()>1) sl@0: { sl@0: QueueDeltaTimer(); sl@0: iDeltaTimer->Activate(); sl@0: } sl@0: iFlags|=ESpriteActive; sl@0: if(iWin) sl@0: iWin->AddSprite(this); sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: if(iFloating) sl@0: { sl@0: Screen()->SpriteManager()->AddFloatingSprite(this); sl@0: ForceRedraw(); sl@0: } sl@0: } sl@0: sl@0: void CWsSpriteBase::SetMember(TInt aIndex) sl@0: { sl@0: iCurIndex=aIndex; sl@0: iPos=iBasePos+(*iMembers)[iCurIndex]->iOffset; sl@0: if ((*iMembers)[iCurIndex]->iBitmap) sl@0: iSize=(*iMembers)[iCurIndex]->iBitmap->SizeInPixels(); sl@0: else sl@0: iSize.SetSize(0,0); sl@0: sl@0: if (iSize.iWidth > iMaxSize.iWidth || iSize.iHeight > iMaxSize.iHeight) sl@0: { sl@0: WS_ASSERT_DEBUG(EFalse, EWsPanicSpriteBitmapSizeChange); sl@0: CheckSizesL(); sl@0: } sl@0: } sl@0: sl@0: void CWsSpriteBase::SetPos(const TPoint &aPos) sl@0: { sl@0: //Non-floating anim whose window is destroyed sl@0: if (!iFloating && iWin==NULL) sl@0: { sl@0: OwnerPanic(EWservPanicWindowDestroyed); sl@0: } sl@0: sl@0: //Floating anim whose group window is destroyed sl@0: if (iFloating && iGroupWin==NULL) sl@0: { sl@0: OwnerPanic(EWservPanicWindowDestroyed); sl@0: } sl@0: sl@0: iBasePos=aPos; sl@0: TPoint newPos(iBasePos+(*iMembers)[iCurIndex]->iOffset); sl@0: if (iPos!=newPos) sl@0: { sl@0: //Ensure the region covered by the sprite before as well as after the move gets scheduled for redraw sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: iPos=newPos; sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: } sl@0: } sl@0: sl@0: // Andy - replace delta timer with animation scheduling via screen sl@0: void CWsSpriteBase::QueueDeltaTimer() sl@0: { sl@0: iDeltaTimer->Queue((*iMembers)[iCurIndex]->iInterval,iDeltaTimerEntry); sl@0: } sl@0: sl@0: void CWsSpriteBase::TimerExpired() sl@0: { sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: SetMember((iCurIndex+1)==iMembers->Count() ? 0 : iCurIndex+1); sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: QueueDeltaTimer(); sl@0: iScreen->Update(); sl@0: } sl@0: sl@0: TPoint CWsSpriteBase::Pos() const sl@0: { sl@0: if (iGroupWin || iWin==NULL) sl@0: { sl@0: return(iPos); sl@0: } sl@0: return(iPos+iWin->Origin()); sl@0: } sl@0: sl@0: TRect CWsSpriteBase::Rect() const sl@0: { sl@0: TRect rect; sl@0: rect.iTl=Pos(); sl@0: rect.iBr=rect.iTl+iSize; sl@0: return(rect); sl@0: } sl@0: sl@0: void CWsSpriteBase::CommandL(TInt aOpcode, const TAny *aCmdData) sl@0: { sl@0: TWsSpriteCmdUnion pData; sl@0: sl@0: pData.any=aCmdData; sl@0: switch(aOpcode) sl@0: { sl@0: case EWsSpriteOpAppendMember: sl@0: AppendMemberL(*pData.SpriteMember); sl@0: break; sl@0: case EWsSpriteOpActivate: sl@0: if(!(iFlags&ESpriteActive)) sl@0: { sl@0: CompleteL(); sl@0: } sl@0: break; sl@0: case EWsSpriteOpUpdateMember: sl@0: if (pData.UpdateMember->index==iCurIndex) sl@0: { sl@0: TRect rect(Pos(), iMaxSize); sl@0: Screen()->SpriteManager()->Schedule(this,&rect); sl@0: } sl@0: break; sl@0: case EWsSpriteOpUpdateMember2: sl@0: { sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: if (pData.UpdateMember->index<0 || pData.UpdateMember->index>=iMembers->Count()) sl@0: User::Leave(KErrArgument); sl@0: CWsSpriteMember *member=(*iMembers)[pData.UpdateMember->index]; sl@0: TBool ret=EFalse; sl@0: TRAPD(err,ret=UpdateMemberL(member,pData.UpdateMember->data)); sl@0: if (err==KErrNone) sl@0: { sl@0: TRAP(err,CheckSizesL()); sl@0: SetMember(0); sl@0: } sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: User::LeaveIfError(err); sl@0: if (ret) sl@0: OwnerPanic(EWservPanicBitmap); sl@0: } sl@0: break; sl@0: default: sl@0: OwnerPanic(EWservPanicOpcode); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: TBool CWsSpriteBase::CanBeSeen() const sl@0: { sl@0: if(iWin) sl@0: return (!(iFlags&ESpriteDisabled)) && (!iWin->VisibleRegion().IsEmpty()); sl@0: else sl@0: return (!(iFlags&ESpriteDisabled)); sl@0: } sl@0: sl@0: void CWsSpriteBase::Redraw(CFbsBitGc * aGc, const TRegion& aRegion) sl@0: { sl@0: TFlashState currentState=EFlashOn; sl@0: if(IsFlashingEnabled()) sl@0: currentState=Screen()->SpriteManager()->CurrentSpriteFlashState(this); sl@0: sl@0: if(currentState==EFlashOn) sl@0: { sl@0: STACK_REGION region; sl@0: region.Copy(aRegion); sl@0: const TRegion * pr = ®ion; sl@0: if (iClipSprite) sl@0: { sl@0: //PeterI iWin shouldn't be null as iClipSprite is currently only set by the text cursor (which is never floating) sl@0: //but just in case make sure we don't derefernce if it is null. sl@0: TPoint origin(0,0); sl@0: if(iWin) sl@0: origin = iWin->Origin(); sl@0: TRect rect(iBasePos + origin + iClipOffset, iClipSize); sl@0: region.ClipRect(rect); sl@0: } sl@0: region.ClipRect(RootWindow()->Abs()); sl@0: sl@0: // Only need to draw if the region being redrawn overlaps the sprite sl@0: const TRect spriteRect(Pos(), iSize); sl@0: STACK_REGION spriteRegion; sl@0: spriteRegion.AddRect(spriteRect); sl@0: region.Intersect(spriteRegion); sl@0: spriteRegion.Close(); sl@0: sl@0: if (pr->CheckError()) sl@0: { sl@0: if(iWin) sl@0: pr = &iWin->VisibleRegion(); sl@0: else sl@0: pr = &RootWindow()->WindowArea(); sl@0: } sl@0: sl@0: if (!pr->IsEmpty()) sl@0: { sl@0: CWsSpriteMember *member=(*iMembers)[iCurIndex]; sl@0: if (member->iBitmap) sl@0: { sl@0: aGc->SetClippingRegion(pr); sl@0: sl@0: // Calculate which piece (rect) of the bitmap needs to be drawn sl@0: const TRect redrawRect = pr->BoundingRect(); sl@0: TRect bitmapRect(spriteRect); // sprite rect relative to screen sl@0: bitmapRect.Intersection(redrawRect); sl@0: bitmapRect.Move(-Pos()); // adjust relative to bitmap origin sl@0: sl@0: if (member->iMaskBitmap) sl@0: aGc->BitBltMasked(Pos() + bitmapRect.iTl, member->iBitmap, bitmapRect, member->iMaskBitmap, member->iInvertMask); sl@0: else sl@0: { sl@0: aGc->SetDrawMode(member->iDrawMode); sl@0: aGc->BitBlt(Pos() + bitmapRect.iTl, member->iBitmap, bitmapRect); sl@0: aGc->SetDrawMode(CGraphicsContext::EDrawModePEN); sl@0: } sl@0: aGc->SetClippingRegion(NULL); sl@0: } sl@0: } sl@0: region.Close(); sl@0: } sl@0: //flashing sprites need to reschedule themselves after drawing sl@0: if(IsFlashingEnabled()) sl@0: Screen()->SpriteManager()->Schedule(this); sl@0: } sl@0: sl@0: TBool CWsSpriteBase::IsActivated() const sl@0: { sl@0: return (iFlags&ESpriteActive); sl@0: } sl@0: sl@0: // sl@0: // CWsSprite sl@0: // sl@0: sl@0: CWsSprite::CWsSprite(CWsClient *owner) : CWsSpriteBase(owner,WS_HANDLE_SPRITE) sl@0: { sl@0: } sl@0: sl@0: CWsSprite::~CWsSprite() sl@0: { sl@0: if (!iFloating && IsActivated() && iWin && iWin->IsVisible()) sl@0: ForceRedraw(); sl@0: sl@0: if (iAnim) sl@0: CWsAnim::CloseAnim(iAnim); sl@0: } sl@0: sl@0: void CWsSprite::ConstructL(const TWsClCmdCreateSprite &aParams) sl@0: { sl@0: NewObjL(); sl@0: CWsWindowBase *win; sl@0: WsOwner()->HandleToWindow(aParams.window,&win); sl@0: if (win->WinType()==EWinTypeGroup) sl@0: { sl@0: //If a sprite is attached to a group window it is floating. sl@0: //Floating sprite drawing is performed by the sprite manager. sl@0: iGroupWin=(CWsWindowGroup *)win; sl@0: win=NULL; //Floating sprites aren't associated with any particular window. sl@0: iFloating=ETrue; sl@0: } sl@0: CWsSpriteBase::ConstructL(aParams.flags&ESpriteNonSystemFlags,(CWsWindow *)win); sl@0: iBasePos=aParams.pos; sl@0: } sl@0: sl@0: void CWsSprite::CompleteL() sl@0: { sl@0: CWsSpriteBase::CompleteL(); sl@0: Activate(); sl@0: } sl@0: sl@0: void CWsSprite::CommandL(TInt aOpcode, const TAny *aCmdData) sl@0: { sl@0: TWsSpriteCmdUnion pData; sl@0: pData.any=aCmdData; sl@0: switch(aOpcode) sl@0: { sl@0: case EWsSpriteOpSetPosition: sl@0: SetPos(*pData.Point); sl@0: break; sl@0: case EWsSpriteOpFree: sl@0: delete this; sl@0: break; sl@0: default: sl@0: CWsSpriteBase::CommandL(aOpcode, aCmdData); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: @see MAnimSpriteFunctions::UpdateMember sl@0: @param aFullUpdate Not used. Wserv2 always do full back to front rendering, so there is no distinction between changes needing aFullUpdate or not sl@0: */ sl@0: void CWsSprite::Update(TInt aMember,TRect aRect,TBool /*aFullUpdate*/) sl@0: { sl@0: if (iCurIndex!=aMember) sl@0: return; sl@0: aRect.Move(Pos()); sl@0: aRect.Intersection(iScreen->CurrentScreenSize()); sl@0: Screen()->SpriteManager()->Schedule(this, &aRect); sl@0: } sl@0: sl@0: // sl@0: // CWsPointerCursor sl@0: // sl@0: sl@0: CWsPointerCursor::CWsPointerCursor(CWsClient *owner) : CWsSpriteBase(owner,WS_HANDLE_POINTER_CURSOR) sl@0: { sl@0: } sl@0: sl@0: void CWsPointerCursor::CloseObject() sl@0: { sl@0: RemoveFromIndex(); sl@0: Close(); sl@0: } sl@0: sl@0: void CWsPointerCursor::Close() sl@0: { sl@0: WS_ASSERT_DEBUG(iAccessCount>0, EWsPanicPointerCursorAccessCount); sl@0: if (--iAccessCount==0) sl@0: delete this; sl@0: } sl@0: sl@0: void CWsPointerCursor::Open() sl@0: { sl@0: iAccessCount++; sl@0: } sl@0: sl@0: CWsPointerCursor::~CWsPointerCursor() sl@0: { sl@0: WS_ASSERT_DEBUG(iAccessCount==0, EWsPanicPointerCursorAccessCount); sl@0: } sl@0: sl@0: void CWsPointerCursor::ConstructL(const TWsClCmdCreatePointerCursor &aParams) sl@0: { sl@0: NewObjL(); sl@0: CWsSpriteBase::ConstructL(ESpriteNoShadows|ESpriteNoChildClip|ESpritePointer|(aParams.flags&ESpriteNonSystemFlags),RootWindow()); sl@0: Open(); sl@0: } sl@0: sl@0: void CWsPointerCursor::CommandL(TInt aOpcode, const TAny *aCmdData) sl@0: { sl@0: switch(aOpcode) sl@0: { sl@0: case EWsSpriteOpFree: sl@0: CloseObject(); sl@0: break; sl@0: default: sl@0: CWsSpriteBase::CommandL(aOpcode, aCmdData); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // sl@0: // CWsCustomTextCursor sl@0: // sl@0: sl@0: CWsCustomTextCursor::CWsCustomTextCursor (CWsClient *aOwner, RWsSession::TCustomTextCursorAlignment aAlignment) sl@0: : CWsSpriteBase(aOwner, WS_HANDLE_TEXT_CURSOR), iAlignment(aAlignment) sl@0: { sl@0: } sl@0: sl@0: CWsCustomTextCursor::~CWsCustomTextCursor() sl@0: { sl@0: } sl@0: sl@0: void CWsCustomTextCursor::ConstructL(TInt aFlags) sl@0: { sl@0: NewObjL(); sl@0: CWsSpriteBase::ConstructL(ESpriteNoShadows|ESpriteNoChildClip|ESpritePointer|(aFlags&ESpriteNonSystemFlags), NULL); sl@0: } sl@0: sl@0: void CWsCustomTextCursor::CompleteL(CWsWindow *aWin, TBool aFlash, TBool aClipSprite, const TPoint& aClipOffset, const TSize& aClipSize) sl@0: { sl@0: iWin = aWin; sl@0: iFlags = aFlash ? iFlags | ESpriteFlash : iFlags & ~ESpriteFlash; sl@0: iClipSprite = aClipSprite; sl@0: iClipOffset = aClipOffset; sl@0: iClipSize = aClipSize; sl@0: CWsSpriteBase::CompleteL(); sl@0: } sl@0: sl@0: // Use SetPositionNoRedraw instead of SetPos when you just want to update sl@0: // the custom text cursor position without redrawing it sl@0: void CWsCustomTextCursor::SetPositionNoRedraw(const TPoint& aPos) sl@0: { sl@0: iBasePos = aPos; sl@0: TPoint newPos(iBasePos+(*iMembers)[iCurIndex]->iOffset); sl@0: iPos=newPos; sl@0: } sl@0: sl@0: void CWsCustomTextCursor::CommandL(TInt aOpcode, const TAny *aCmdData) sl@0: { sl@0: switch(aOpcode) sl@0: { sl@0: case EWsSpriteOpFree: sl@0: // CWsCustomTextCursor objects are owned by the text cursor list. sl@0: // They are not deleted when the client closes it's R class. sl@0: RemoveFromIndex(); sl@0: break; sl@0: default: sl@0: CWsSpriteBase::CommandL(aOpcode, aCmdData); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // sl@0: // CWsDeltaTimer, nicked from CDeltaTimer and tweaked so it doesn't re-activate // sl@0: // the timers until RunL has finished running all ready timers. // sl@0: // // sl@0: // This is to stop a problem in Wserv where sprites could hog 100% CPU if the time // sl@0: // it took to process them was longer than the time of the timer queued when the first // sl@0: // sprite was updated // sl@0: // sl@0: sl@0: CWsDeltaTimer* CWsDeltaTimer::NewL(TInt aPriority) sl@0: { sl@0: CWsDeltaTimer* wsdt=new(ELeave) CWsDeltaTimer(aPriority); sl@0: CleanupStack::PushL(wsdt); sl@0: User::LeaveIfError(wsdt->iTimer.CreateLocal()); sl@0: CActiveScheduler::Add(wsdt); sl@0: CleanupStack::Pop(wsdt); sl@0: return(wsdt); sl@0: } sl@0: sl@0: CWsDeltaTimer::CWsDeltaTimer(TInt aPriority) : CActive(aPriority),iQueue(_FOFF(TWsDeltaTimerEntry,iLink)) sl@0: { sl@0: } sl@0: sl@0: CWsDeltaTimer::~CWsDeltaTimer() sl@0: { sl@0: Cancel(); sl@0: while(iQueue.RemoveFirst()!=NULL) sl@0: {} sl@0: } sl@0: sl@0: void CWsDeltaTimer::Queue(TTimeIntervalMicroSeconds32 aTimeInMicroSeconds,TWsDeltaTimerEntry& anEntry) sl@0: { sl@0: TInt intervals=aTimeInMicroSeconds.Int()/CWsDeltaTimerGranularity; sl@0: if (intervals==0) sl@0: intervals=1; sl@0: iQueue.Add(anEntry,intervals); sl@0: } sl@0: sl@0: void CWsDeltaTimer::Activate() sl@0: { sl@0: // Queue a request on the timer. sl@0: // The timer runs every tenth of a second and decremented the delta of the head of the queue. sl@0: if (IsActive()) sl@0: return; sl@0: if (!iQueue.IsEmpty()) sl@0: { sl@0: SetActive(); sl@0: iTimer.After(iStatus,CWsDeltaTimerGranularity-1); // -1 to compensate for +1 in kernel! sl@0: } sl@0: } sl@0: sl@0: void CWsDeltaTimer::RunL() sl@0: { sl@0: // Call all zero delta callbacks sl@0: iQueue.CountDown(); sl@0: TWsDeltaTimerEntry* ent=iQueue.RemoveFirst(); sl@0: while (ent) sl@0: { sl@0: ent->iCallBack.CallBack(); sl@0: ent=iQueue.RemoveFirst(); sl@0: } sl@0: Activate(); sl@0: } sl@0: sl@0: void CWsDeltaTimer::DoCancel() sl@0: { sl@0: iTimer.Cancel(); sl@0: } sl@0: sl@0: void CWsDeltaTimer::Remove(TWsDeltaTimerEntry& anEntry) sl@0: { sl@0: if (anEntry.IsPending()) sl@0: { sl@0: iQueue.Remove(anEntry); sl@0: Activate(); sl@0: } sl@0: } sl@0: sl@0: sl@0: // sl@0: // CWsSpriteManager -handles floating and flashing sprites including flashing custom text cursors. i.e. cursors sl@0: // that have an associated sprite. sl@0: sl@0: sl@0: CWsSpriteManager::CWsSpriteManager() sl@0: { sl@0: } sl@0: sl@0: CWsSpriteManager::~CWsSpriteManager() sl@0: { sl@0: iFloatingSprites.ResetAndDestroy(); sl@0: } sl@0: sl@0: CWsSpriteManager* CWsSpriteManager::NewL() sl@0: { sl@0: CWsSpriteManager* self = new (ELeave) CWsSpriteManager(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CWsSpriteManager::ConstructL() sl@0: { sl@0: } sl@0: sl@0: void CWsSpriteManager::AddFloatingSprite(CWsSpriteBase* aSprite) sl@0: { sl@0: iFloatingSprites.Append(aSprite); sl@0: } sl@0: sl@0: void CWsSpriteManager::RemoveFloatingSprite(CWsSpriteBase* aSprite) sl@0: { sl@0: for (TInt i=0 ; iReset(); sl@0: iFloatingSprites[i]->Redraw(aGc, aRegion); sl@0: } sl@0: } sl@0: sl@0: void CWsSpriteManager::Schedule(CWsSpriteBase* aSprite, TRect* aRect) sl@0: { sl@0: if (aRect != NULL && aRect->IsEmpty()) sl@0: return; sl@0: sl@0: TRect rect = aSprite->Rect(); sl@0: if (aRect) sl@0: rect.Intersection(*aRect); sl@0: sl@0: if(aSprite->IsFlashingEnabled()) sl@0: { sl@0: aSprite->Screen()->ScheduleAnimation(rect,NextSpriteFlashStateChange(aSprite),0,0); sl@0: } sl@0: else sl@0: { sl@0: //Scheduling an animation "now" means it will take place at next animation which might sl@0: //be the full animation grace period into the future (see KAnimationGrace in server.cpp) sl@0: aSprite->Screen()->ScheduleAnimation(rect,0,0,0); sl@0: } sl@0: } sl@0: sl@0: // Sprite flashing is clamped to half second intervals in relation to the global time. sl@0: // For the first half of each second all sprites have the EFlashOn state (visible) sl@0: // For the second half of each second all sprites have the EFlashOff state (not visible) sl@0: TTimeIntervalMicroSeconds CWsSpriteManager::NextSpriteFlashStateChange(const CWsSpriteBase* aSprite) const sl@0: { sl@0: const TTimeIntervalMicroSeconds remainder = aSprite->Screen()->Now().DateTime().MicroSecond(); sl@0: return CalculateTimeToNextFlash(remainder); sl@0: } sl@0: sl@0: TTimeIntervalMicroSeconds CWsSpriteManager::NextCursorFlashStateChange() const sl@0: { sl@0: const TTimeIntervalMicroSeconds remainder = CWsTop::CurrentFocusScreen()->Now().DateTime().MicroSecond(); sl@0: return CalculateTimeToNextFlash(remainder); sl@0: } sl@0: sl@0: TTimeIntervalMicroSeconds CWsSpriteManager::CalculateTimeToNextFlash(TTimeIntervalMicroSeconds aTime) const sl@0: { sl@0: TInt64 nextStateChange; sl@0: if(aTimeScreen()->Now().DateTime().MicroSecond()Now().DateTime().MicroSecond()CanBeSeen() && ( sprite->IsActive() || sprite->IsActivated() ) ) sl@0: { sl@0: aResultRgn.AddRect( sprite->Rect() ); sl@0: } sl@0: } sl@0: aResultRgn.Tidy(); sl@0: if ( aResultRgn.CheckError() && iFloatingSprites.Count() > 0 ) sl@0: { sl@0: aResultRgn.Clear(); sl@0: aResultRgn.AddRect( aDefaultRect ); sl@0: } sl@0: }