Update contrib.
1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
21 #include "windowgroup.h"
27 #include "bitgditomwsgraphicscontextmappings.h"
28 #include "../debuglog/DEBUGLOG.H"
30 static const TInt64 KFlashHalfSecond(500000); //interval for flashing sprites
32 GLDEF_D CWsDeltaTimer *CWsSpriteBase::iDeltaTimer=NULL;
34 TInt TimerCallBack(TAny *aPtr)
36 ((CWsSpriteBase *)aPtr)->TimerExpired();
42 #define LOG_SPRITE_REDRAW_START(sprite)
43 #define LOG_SPRITE_REDRAW_END(sprite)
44 #define LOG_SPRITE_FLASH(aSprite)
48 #define LOG_SPRITE_REDRAW_START(sprite) LogSpriteRedrawStart(sprite)
49 #define LOG_SPRITE_REDRAW_END(sprite) LogSpriteRedrawEnd(sprite)
50 #define LOG_SPRITE_FLASH(sprite) LogSpriteFlash(sprite)
52 extern CDebugLogBase *wsDebugLog;
55 static void LogSpriteRedrawStart(const CWsSpriteBase& aSprite)
59 _LIT(KAnnotateSpriteRedrawStart, ">> MWsDrawAnnotationObserver::FloatingSpriteRedrawStart [%S][app %d]");
60 const TDesC& clientName = aSprite.WsOwner()->Client().FullName();
61 TBuf<LogTBufSize> log;
62 TTruncateOverflow overflow;
63 log.AppendFormat(KAnnotateSpriteRedrawStart, &overflow, &clientName, aSprite.WsOwner()->ConnectionHandle());
64 wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
68 static void LogSpriteRedrawEnd(const CWsSpriteBase& aSprite)
72 _LIT(KAnnotateSpriteRedrawEnd, "<< MWsDrawAnnotationObserver::FloatingSpriteRedrawEnd [%S][app %d]");
73 const TDesC& clientName = aSprite.WsOwner()->Client().FullName();
74 TBuf<LogTBufSize> log;
75 TTruncateOverflow overflow;
76 log.AppendFormat(KAnnotateSpriteRedrawEnd, &overflow, &clientName, aSprite.WsOwner()->ConnectionHandle());
77 wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
81 static void LogSpriteFlash(const CWsSpriteBase& /*aSprite*/)
85 // The following code causes Exception and is commented out, see defect GFX09962
87 // _LIT(KAnnotateSpriteFlash, "-- MWsDrawAnnotationObserver::SpriteFlash:%d [%S][app %d]");
88 // const TDesC& clientName = aSprite.WsOwner()->Client().FullName();
89 // TBuf<LogTBufSize> log;
90 // TTruncateOverflow overflow;
91 // log.AppendFormat(KAnnotateSpriteFlash, &overflow, &clientName, aSprite.WsOwner()->ConnectionHandle());
92 // wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
94 // This code is temporarily here until above problem is resolved
95 _LIT(KAnnotateSpriteFlash, "-- MWsDrawAnnotationObserver::SpriteFlash");
96 TBuf<LogTBufSize> log;
97 log.AppendFormat(KAnnotateSpriteFlash);
98 wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, log);
107 static void AnnotateSpriteRedrawStart(const CWsSpriteBase& aSprite, const TRegion& aRegion)
109 LOG_SPRITE_REDRAW_START(aSprite);
110 MWsDrawAnnotationObserver* annoObs = aSprite.Screen()->DrawAnnotationObserver();
113 annoObs->SpriteRedrawStart(aSprite, aRegion);
117 static void AnnotateSpriteRedrawEnd(const CWsSpriteBase& aSprite)
119 LOG_SPRITE_REDRAW_END(aSprite);
120 MWsDrawAnnotationObserver* annoObs = aSprite.Screen()->DrawAnnotationObserver();
123 annoObs->SpriteRedrawEnd(aSprite);
127 static void AnnotateSpriteFlash(const CWsSpriteBase& aSprite, TBool aFlashOn)
129 LOG_SPRITE_FLASH(aSprite);
130 MWsDrawAnnotationObserver* annoObs = aSprite.Screen()->DrawAnnotationObserver();
133 annoObs->SpriteFlash(aSprite, aFlashOn);
142 CWsSpriteMember::CWsSpriteMember()
146 CWsSpriteMember::~CWsSpriteMember()
152 TBool CWsSpriteMember::SetL(const TCmdSpriteMember &aCmdSpriteMember)
154 if (aCmdSpriteMember.iBitmap!=0) // Null member of sequence, time is only valid field in member data
156 iBitmap=new(ELeave) CFbsBitmap();
157 TInt ret = iBitmap->Duplicate(aCmdSpriteMember.iBitmap);
158 if (ret == KErrNoMemory)
165 if (aCmdSpriteMember.iMaskBitmap)
167 iMaskBitmap=new(ELeave) CFbsBitmap();
168 TInt ret = iMaskBitmap->Duplicate(aCmdSpriteMember.iMaskBitmap);
169 if (ret == KErrNoMemory)
176 iInvertMask=aCmdSpriteMember.iInvertMask;
177 iDrawMode=aCmdSpriteMember.iDrawMode;
178 iOffset=aCmdSpriteMember.iOffset;
180 iInterval=aCmdSpriteMember.iInterval;
188 TBool CWsSpriteBase::UpdateMemberL(CWsSpriteMember *aMember, const TCmdSpriteMember &aCmdSpriteMember)
190 CFbsBitmap *old=aMember->iBitmap;
191 CFbsBitmap *oldMask=aMember->iMaskBitmap;
192 aMember->iBitmap=NULL;
193 aMember->iMaskBitmap=NULL;
195 TRAPD(err,ret=aMember->SetL(aCmdSpriteMember));
199 delete aMember->iBitmap;
200 delete aMember->iMaskBitmap;
201 aMember->iBitmap=old;
202 aMember->iMaskBitmap=oldMask;
205 TRAP(err,CheckSizesL());
214 void CWsSpriteBase::InitStaticsL()
216 iDeltaTimer=CWsDeltaTimer::NewL(ESpriteAnimatePriority);
219 void CWsSpriteBase::DeleteStatics()
224 CWsSpriteBase::CWsSpriteBase(CWsClient *owner, WH_HANDLES aType) : CWsScreenObject(owner,aType,owner->Screen())
228 CWsSpriteBase::~CWsSpriteBase()
231 if(IsFloating() && iGroupWin)
233 iGroupWin->RemoveSprite(this);
236 //iDeltaTimer->Remove(iDeltaTimerEntry);
239 iMembers->ResetAndDestroy();
244 void CWsSpriteBase::ForceRedraw()
246 TRegionFix<1> region;
247 region.AddRect(Rect());
248 Screen()->AddRedrawRegion(region);
251 void CWsSpriteBase::Deactivate()
253 //Disconnect from the sprite list and hide the sprite
254 if (iFlags & ESpriteActive)
256 iFlags&=~ESpriteActive;
258 MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
259 if (windowTreeObserver)
261 windowTreeObserver->NodeReleased(*this);
264 if (iMembers && iMembers->Count()>1)
266 iDeltaTimer->Remove(iDeltaTimerEntry);
271 Screen()->SpriteManager()->RemoveFloatingSprite(this);
272 if (!Screen()->ChangeTracking())
278 // Note: This could be a floating sprite attached to the root window (PDEF138379)
281 iWin->RemoveSprite(this);
286 /** Called from groupwin destructor only */
287 void CWsSpriteBase::DisconnectGroupWin()
289 WS_ASSERT_DEBUG(IsFloating(),EWsPanicFloatingSprite);
293 void CWsSpriteBase::CheckSizesL()
295 iMaxSize.SetSize(0,0);
296 for(TInt index=0;index<iMembers->Count();index++)
298 CWsSpriteMember *wsm=(*iMembers)[index];
301 TSize size=wsm->iBitmap->SizeInPixels();
302 if (wsm->iMaskBitmap)
304 TSize maskSize=wsm->iMaskBitmap->SizeInPixels();
305 if (maskSize.iWidth<size.iWidth || maskSize.iHeight<size.iHeight)
306 OwnerPanic(EWservPanicMaskSize);
308 if (size.iWidth>iMaxSize.iWidth)
309 iMaxSize.iWidth=size.iWidth;
310 if (size.iHeight>iMaxSize.iHeight)
311 iMaxSize.iHeight=size.iHeight;
316 void CWsSpriteBase::ConstructL(TUint aFlags, CWsWindow *aWindow)
318 // Common part of construct for both sprites and pointer cursors
321 if (iFlags&ESpriteNoChildClip)
322 iLink.iPriority+=ENoChildPriorityBoost;
323 if (iFlags&ESpritePointer)
324 iLink.iPriority+=EPointerPriorityBoost;
327 TCallBack callback(TimerCallBack,this);
328 iDeltaTimerEntry.Set(callback);
329 iMembers=new(ELeave) CArrayPtrFlat<CWsSpriteMember>(10);
332 void CWsSpriteBase::AppendMemberL(const TCmdSpriteMember &aCmdSpriteMember)
334 CWsSpriteMember *&pwsm=iMembers->ExtendL();
335 pwsm=NULL; // In case new leaves
336 pwsm=new(ELeave) CWsSpriteMember();
337 // coverity[leave_without_push]
338 // pwsm is not owned by the stack and will be deleted by RWsSpriteBase::Close()
339 if (pwsm->SetL(aCmdSpriteMember))
340 OwnerPanic(EWservPanicBitmap);
343 void CWsSpriteBase::CompleteL()
345 if (iMembers->Count() <= 0)
348 iWin->OwnerPanic(EWservPanicNoSpriteMember);
349 //Not sure if this is a neccessary fall back if iWin is NULL.
350 else if(iWin==NULL && iGroupWin)
351 iGroupWin->OwnerPanic(EWservPanicNoSpriteMember);
355 iMembers->Compress();
361 void CWsSpriteBase::Activate()
363 if (iFlags&ESpriteDisabled)
365 iFlags&=~ESpriteDisabled;
367 if (iMembers->Count()>1)
370 iDeltaTimer->Activate();
372 iFlags|=ESpriteActive;
374 iWin->AddSprite(this);
376 Screen()->SpriteManager()->Schedule(this);
379 Screen()->SpriteManager()->AddFloatingSprite(this);
380 if (!Screen()->ChangeTracking())
385 // As custom text cursors are sprites (CWsCustomTextCursor) and can be activated/deactivated
386 // on various different windows during their lifetime, when activating
387 // a text cursor, we pretend it's just been created to give us the option
388 // of specifying a new parent window. Normal sprites (CWsSprite) are
389 // treated the same way just for consistency as it does no harm.
390 MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
391 if (windowTreeObserver)
393 windowTreeObserver->NodeCreated(*this, ParentNode());
394 windowTreeObserver->NodeExtentChanged(*this, Rect());
395 windowTreeObserver->NodeActivated(*this);
399 void CWsSpriteBase::SetMember(TInt aIndex)
401 const TSize oldSize = iSize;
402 const TPoint oldPos = iPos;
405 TRect rect(iPos,iSize);
408 iPos=iBasePos+(*iMembers)[iCurIndex]->iOffset;
409 if ((*iMembers)[iCurIndex]->iBitmap)
410 iSize=(*iMembers)[iCurIndex]->iBitmap->SizeInPixels();
414 if (iSize.iWidth > iMaxSize.iWidth || iSize.iHeight > iMaxSize.iHeight)
416 WS_ASSERT_DEBUG(EFalse, EWsPanicSpriteBitmapSizeChange);
420 if(oldSize!=iSize || oldPos!=iPos)
421 NotifyExtentChanged();
425 void CWsSpriteBase::SetPos(const TPoint &aPos)
427 //Non-floating anim whose window is destroyed
428 if (!IsFloating() && iWin==NULL)
430 OwnerPanic(EWservPanicWindowDestroyed);
433 //Floating anim whose group window is destroyed
434 if (IsFloating() && iGroupWin==NULL && iWin->WinType() != EWinTypeRoot)
436 OwnerPanic(EWservPanicWindowDestroyed);
441 TRect rect(iPos,iSize);
445 TPoint newPos(iBasePos+(*iMembers)[iCurIndex]->iOffset);
448 if (!Screen()->ChangeTracking())
449 //Ensure the region covered by the sprite before as well as after the move gets scheduled for redraw
450 Screen()->SpriteManager()->Schedule(this);
452 if (!Screen()->ChangeTracking())
453 Screen()->SpriteManager()->Schedule(this);
454 NotifyExtentChanged();
458 void CWsSpriteBase::QueueDeltaTimer()
460 iDeltaTimer->Queue((*iMembers)[iCurIndex]->iInterval,iDeltaTimerEntry);
463 void CWsSpriteBase::TimerExpired()
465 if (!Screen()->ChangeTracking())
466 Screen()->SpriteManager()->Schedule(this);
467 SetMember((iCurIndex+1)==iMembers->Count() ? 0 : iCurIndex+1);
469 Screen()->SpriteManager()->Schedule(this);
473 TPoint CWsSpriteBase::Pos() const
475 if (iGroupWin || iWin==NULL || iWin->WinType() == EWinTypeRoot )
479 return(iPos+iWin->Origin());
482 TRect CWsSpriteBase::Rect() const
486 rect.iBr=rect.iTl+iSize;
490 MWsSprite::TSpriteType CWsSpriteBase::SpriteType() const
493 return EFloatingSprite;
495 TSpriteType spriteType = EWindowSprite;
498 case WS_HANDLE_SPRITE:
499 spriteType = EWindowSprite;
501 case WS_HANDLE_POINTER_CURSOR:
502 spriteType = EPointerCursorSprite;
504 case WS_HANDLE_TEXT_CURSOR:
505 spriteType = ECustomTextCursorSprite;
513 void CWsSpriteBase::CommandL(TInt aOpcode, const TAny *aCmdData)
515 TWsSpriteCmdUnion pData;
520 case EWsSpriteOpAppendMember:
521 AppendMemberL(*pData.SpriteMember);
523 case EWsSpriteOpActivate:
524 if(!(iFlags&ESpriteActive))
527 case EWsSpriteOpUpdateMember:
528 if (pData.UpdateMember->index==iCurIndex)
531 TRect rect(Pos(), iMaxSize);
532 Screen()->SpriteManager()->Schedule(this,&rect);
535 case EWsSpriteOpUpdateMember2:
538 Screen()->SpriteManager()->Schedule(this);
539 if (pData.UpdateMember->index<0 || pData.UpdateMember->index>=iMembers->Count())
540 User::Leave(KErrArgument);
541 CWsSpriteMember *member=(*iMembers)[pData.UpdateMember->index];
543 TRAPD(err,ret=UpdateMemberL(member,pData.UpdateMember->data));
546 TRAP(err,CheckSizesL());
549 Screen()->SpriteManager()->Schedule(this);
550 User::LeaveIfError(err);
552 OwnerPanic(EWservPanicBitmap);
556 OwnerPanic(EWservPanicOpcode);
561 TBool CWsSpriteBase::CanBeSeen() const
564 return (!(iFlags&ESpriteDisabled)) && (!iWin->VisibleRegion().IsEmpty());
566 return (!(iFlags&ESpriteDisabled));
569 void CWsSpriteBase::CalcRedrawRegion(const TRegion& aSourceRegion, TRegion& aTarget) const
571 aTarget.Copy(aSourceRegion);
576 origin = iWin->Origin();
577 TRect rect(iBasePos + origin + iClipOffset, iClipSize);
578 aTarget.ClipRect(rect);
580 aTarget.ClipRect(RootWindow()->Abs());
582 // Only need to draw if the region being redrawn overlaps the sprite
583 const TRect spriteRect(Pos(), iSize);
584 STACK_REGION spriteRegion;
585 spriteRegion.AddRect(spriteRect);
586 aTarget.Intersect(spriteRegion);
587 spriteRegion.Close();
591 @pre CWsSpriteBase::CalcRedrawRegion(TRegion&,TRegion&) should have been called.
592 @param aRegion Is the region that will definitely be redrawn if dirty. This param should
593 be calculated by calling CalcRedrawRegion(TRegion&,TRegion&)
595 void CWsSpriteBase::Redraw(MWsGraphicsContext * aGc, const TRegion& aRegion)
597 TFlashState currentState=EFlashOn;
598 if(IsFlashingEnabled())
600 currentState=Screen()->SpriteManager()->CurrentSpriteFlashState(this);
601 AnnotateSpriteFlash(*this, currentState==EFlashOn);
604 if(currentState==EFlashOn && (IsDirty() || HasAnimation()) )
606 const TRegion * pr = &aRegion;
608 if (pr->CheckError())
612 if (Screen()->ChangeTracking())
613 pr = &iWin->WindowArea();
615 pr = &iWin->VisibleRegion();
618 pr = &RootWindow()->WindowArea();
623 CWsSpriteMember *member=(*iMembers)[iCurIndex];
626 aGc->SetClippingRegion(*pr);
628 // Calculate which piece (rect) of the bitmap needs to be drawn
629 const TRect redrawRect = pr->BoundingRect();
630 TRect bitmapRect(Pos(), iSize); // sprite rect relative to screen
631 bitmapRect.Intersection(redrawRect);
632 bitmapRect.Move(-Pos()); // adjust relative to bitmap origin
634 if (member->iMaskBitmap)
635 aGc->BitBltMasked(Pos() + bitmapRect.iTl, *member->iBitmap, bitmapRect, *member->iMaskBitmap, member->iInvertMask);
638 aGc->SetDrawMode(BitGdiToMWsGraphicsContextMappings::LossyConvert(member->iDrawMode));
639 aGc->BitBlt(Pos() + bitmapRect.iTl, *member->iBitmap, bitmapRect);
640 aGc->SetDrawMode(MWsGraphicsContext::EDrawModePEN);
642 aGc->ResetClippingRegion();
645 if (Screen()->ChangeTracking())
650 //Flashing sprites need to reschedule themselves after drawing (unless they have
651 //an animation, because for animating sprites the rescheduling is done in CWsAnim).
652 if(IsFlashingEnabled() && !HasAnimation())
653 Screen()->SpriteManager()->Schedule(this);
656 TBool CWsSpriteBase::IsActivated() const
658 return(iFlags&ESpriteActive);
661 void CWsSpriteBase::SendState(MWsWindowTreeObserver& aWindowTreeObserver) const
664 iNext->SendState(aWindowTreeObserver);
668 //Sprite NodeCreated must only be sent if activated
669 aWindowTreeObserver.NodeCreated(*this, ParentNode());
670 aWindowTreeObserver.NodeExtentChanged(*this, Rect());
671 aWindowTreeObserver.NodeActivated(*this);
675 /** @see MWsWindowTreeNode */
676 MWsWindowTreeNode::TType CWsSpriteBase::NodeType() const
678 return MWsWindowTreeNode::EWinTreeNodeSprite;
681 /** @see MWsWindowTreeNode */
682 const MWsWindow* CWsSpriteBase::Window() const
687 /** @see MWsWindowTreeNode */
688 const MWsSprite* CWsSpriteBase::Sprite() const
693 /** @see MWsWindowTreeNode */
694 const MWsStandardTextCursor* CWsSpriteBase::StandardTextCursor() const
699 /** @see MWsWindowTreeNode */
700 const MWsWindowGroup* CWsSpriteBase::WindowGroup() const
703 return iWin->WindowGroup();
705 return static_cast<MWsWindowGroup*>(iGroupWin); //floating Sprite
707 WS_ASSERT_DEBUG(EFalse,EWsPanicInvalidOperation);
711 /** @see MWsWindowTreeNode */
712 const MWsWindowTreeNode* CWsSpriteBase::ParentNode() const
717 return iGroupWin->BaseParent(); //floating Sprite, will return the rootwin
719 WS_ASSERT_DEBUG(EFalse,EWsPanicInvalidOperation);
723 void CWsSpriteBase::NotifyExtentChanged() const
727 MWsWindowTreeObserver* windowTreeObserver = Screen()->WindowTreeObserver();
728 if (windowTreeObserver && iFlags&ESpriteActive)
730 windowTreeObserver->NodeExtentChanged(*this, Rect());
739 CWsSprite::CWsSprite(CWsClient *owner) : CWsSpriteBase(owner,WS_HANDLE_SPRITE)
743 CWsSprite::~CWsSprite()
745 if (!IsFloating() && IsActivated() && iWin && iWin->IsVisible() && !Screen()->ChangeTracking())
748 CWsAnim::CloseAnim(iAnim);
751 void CWsSprite::ConstructL(const TWsClCmdCreateSprite &aParams)
755 WsOwner()->HandleToWindow(aParams.window,&win);
756 WS_ASSERT_DEBUG(win,EWsPanicWindowNull);
757 if (win->WinType()==EWinTypeGroup)
759 //If a sprite is attached to a group window it is floating.
760 //Floating sprite drawing is performed by the sprite manager.
761 iGroupWin=(CWsWindowGroup *)win;
762 win=NULL; //Floating sprites aren't associated with any particular window.
763 SetIsFloating(ETrue);
764 //In case the GroupWin is destroyed before the sprite it needs to call DisconnectGroupWin
765 iGroupWin->AddSprite(this);
767 CWsSpriteBase::ConstructL(aParams.flags&ESpriteNonSystemFlags,(CWsWindow *)win);
768 iBasePos=aParams.pos;
771 void CWsSprite::CompleteL()
773 CWsSpriteBase::CompleteL();
777 void CWsSprite::CommandL(TInt aOpcode, const TAny *aCmdData)
779 TWsSpriteCmdUnion pData;
783 case EWsSpriteOpSetPosition:
784 SetPos(*pData.Point);
786 case EWsSpriteOpFree:
792 CWsSpriteBase::CommandL(aOpcode, aCmdData);
798 @see MAnimSpriteFunctions::UpdateMember
799 @param aFullUpdate Not used. Wserv2 always do full back to front rendering, so there is no distinction between changes needing aFullUpdate or not
801 void CWsSprite::Update(TInt aMember,TRect aRect,TBool /*aFullUpdate*/)
803 if (iCurIndex!=aMember)
806 aRect.Intersection(iScreen->CurrentScreenSize());
808 Screen()->SpriteManager()->Schedule(this, &aRect);
815 CWsPointerCursor::CWsPointerCursor(CWsClient *owner) : CWsSpriteBase(owner,WS_HANDLE_POINTER_CURSOR)
819 void CWsPointerCursor::CloseObject()
825 void CWsPointerCursor::Close()
827 WS_ASSERT_DEBUG(iAccessCount>0, EWsPanicPointerCursorAccessCount);
828 if (--iAccessCount==0)
832 void CWsPointerCursor::Open()
837 CWsPointerCursor::~CWsPointerCursor()
839 WS_ASSERT_DEBUG(iAccessCount==0, EWsPanicPointerCursorAccessCount);
842 void CWsPointerCursor::ConstructL(const TWsClCmdCreatePointerCursor &aParams)
845 SetIsFloating(ETrue);
846 CWsSpriteBase::ConstructL(ESpriteNoShadows|ESpriteNoChildClip|ESpritePointer|(aParams.flags&ESpriteNonSystemFlags),RootWindow());
850 void CWsPointerCursor::CommandL(TInt aOpcode, const TAny *aCmdData)
854 case EWsSpriteOpFree:
858 CWsSpriteBase::CommandL(aOpcode, aCmdData);
864 // CWsCustomTextCursor
867 CWsCustomTextCursor::CWsCustomTextCursor (CWsClient *aOwner, RWsSession::TCustomTextCursorAlignment aAlignment)
868 : CWsSpriteBase(aOwner, WS_HANDLE_TEXT_CURSOR), iAlignment(aAlignment)
872 CWsCustomTextCursor::~CWsCustomTextCursor()
876 void CWsCustomTextCursor::ConstructL(TInt aFlags)
879 CWsSpriteBase::ConstructL(ESpriteNoShadows|ESpriteNoChildClip|ESpritePointer|(aFlags&ESpriteNonSystemFlags), NULL);
882 void CWsCustomTextCursor::CompleteL(CWsWindow *aWin, TBool aFlash, TBool aClipSprite, const TPoint& aClipOffset, const TSize& aClipSize)
885 iFlags = aFlash ? iFlags | ESpriteFlash : iFlags & ~ESpriteFlash;
886 SetClipSprite(aClipSprite);
887 iClipOffset = aClipOffset;
888 iClipSize = aClipSize;
889 CWsSpriteBase::CompleteL();
892 // Use SetPositionNoRedraw instead of SetPos when you just want to update
893 // the custom text cursor position without redrawing it
894 void CWsCustomTextCursor::SetPositionNoRedraw(const TPoint& aPos)
897 TPoint newPos(iBasePos+(*iMembers)[iCurIndex]->iOffset);
901 void CWsCustomTextCursor::CommandL(TInt aOpcode, const TAny *aCmdData)
905 case EWsSpriteOpFree:
906 // CWsCustomTextCursor objects are owned by the text cursor list.
907 // They are not deleted when the client closes it's R class.
911 CWsSpriteBase::CommandL(aOpcode, aCmdData);
917 // CWsDeltaTimer, nicked from CDeltaTimer and tweaked so it doesn't re-activate //
918 // the timers until RunL has finished running all ready timers. //
920 // This is to stop a problem in Wserv where sprites could hog 100% CPU if the time //
921 // it took to process them was longer than the time of the timer queued when the first //
922 // sprite was updated //
925 CWsDeltaTimer* CWsDeltaTimer::NewL(TInt aPriority)
927 CWsDeltaTimer* wsdt=new(ELeave) CWsDeltaTimer(aPriority);
928 CleanupStack::PushL(wsdt);
929 User::LeaveIfError(wsdt->iTimer.CreateLocal());
930 CActiveScheduler::Add(wsdt);
931 CleanupStack::Pop(wsdt);
935 CWsDeltaTimer::CWsDeltaTimer(TInt aPriority) : CActive(aPriority),iQueue(_FOFF(TWsDeltaTimerEntry,iLink))
939 CWsDeltaTimer::~CWsDeltaTimer()
942 while(iQueue.RemoveFirst()!=NULL)
946 void CWsDeltaTimer::Queue(TTimeIntervalMicroSeconds32 aTimeInMicroSeconds,TWsDeltaTimerEntry& anEntry)
948 TInt intervals=aTimeInMicroSeconds.Int()/CWsDeltaTimerGranularity;
951 iQueue.Add(anEntry,intervals);
954 void CWsDeltaTimer::Activate()
956 // Queue a request on the timer.
957 // The timer runs every tenth of a second and decremented the delta of the head of the queue.
960 if (!iQueue.IsEmpty())
963 iTimer.After(iStatus,CWsDeltaTimerGranularity-1); // -1 to compensate for +1 in kernel!
967 void CWsDeltaTimer::RunL()
969 // Call all zero delta callbacks
971 TWsDeltaTimerEntry* ent=iQueue.RemoveFirst();
974 ent->iCallBack.CallBack();
975 ent=iQueue.RemoveFirst();
980 void CWsDeltaTimer::DoCancel()
985 void CWsDeltaTimer::Remove(TWsDeltaTimerEntry& anEntry)
987 if (anEntry.IsPending())
989 iQueue.Remove(anEntry);
996 // CWsSpriteManager -handles floating and flashing sprites including flashing custom text cursors. i.e. cursors
997 // that have an associated sprite.
1000 CWsSpriteManager::CWsSpriteManager()
1004 CWsSpriteManager* CWsSpriteManager::NewL()
1006 CWsSpriteManager* self = new (ELeave) CWsSpriteManager();
1007 CleanupStack::PushL(self);
1009 CleanupStack::Pop(self);
1013 void CWsSpriteManager::ConstructL()
1017 CWsSpriteManager::~CWsSpriteManager()
1019 iFloatingSprites.ResetAndDestroy();
1021 void CWsSpriteManager::AddFloatingSprite(CWsSpriteBase* aSprite)
1023 iFloatingSprites.Append(aSprite);
1026 void CWsSpriteManager::RemoveFloatingSprite(CWsSpriteBase* aSprite)
1031 for (TInt i=0 ; i<iFloatingSprites.Count() ; i++)
1033 if(iFloatingSprites[i]==aSprite)
1035 //Just remove the sprite don't delete it. the manager doesn't have ownership
1036 iFloatingSprites.Remove(i);
1044 WS_ASSERT_DEBUG(removed==1,EWsPanicFloatingSprite);
1047 void CWsSpriteManager::DrawFloatingSprites(MWsGraphicsContext* aGc,const TRegion& aRegion)
1049 if (iFloatingSprites.Count() == 0)
1050 return; //avoid sending events unless necessary
1052 for (TInt i = iFloatingSprites.Count() - 1; i >= 0 ; i--)
1054 STACK_REGION redrawRegion;
1055 CWsSpriteBase* sprite = iFloatingSprites[i];
1056 sprite->CalcRedrawRegion(aRegion, redrawRegion);
1057 if(redrawRegion.CheckError() || !redrawRegion.IsEmpty())
1059 if (sprite->IsFlashingEnabled() || sprite->IsDirty() || sprite->HasAnimation())
1061 AnnotateSpriteRedrawStart(*sprite, redrawRegion);
1063 if(sprite->HasAnimation())
1065 CWsAnim* anim = static_cast<CWsSprite*>(sprite)->iAnim;
1068 TRAPD(err, anim->AnimateSpriteAnimL(sprite->Screen()->Now()));
1071 AnnotateSpriteRedrawEnd(*sprite);
1072 anim->Panic(EWservPanicAnimLeave);
1078 sprite->Redraw(aGc, redrawRegion);
1080 AnnotateSpriteRedrawEnd(*sprite);
1083 redrawRegion.Close();
1087 void CWsSpriteManager::Schedule(CWsSpriteBase* aSprite, TRect* aRect)
1089 if (aRect != NULL && aRect->IsEmpty())
1092 TRect rect = aSprite->Rect();
1094 rect.Intersection(*aRect);
1096 const TAnimType type = aSprite->Win() ? EWindowSprite : EFloatingSprite;
1098 if(aSprite->IsFlashingEnabled())
1100 aSprite->Screen()->ScheduleAnimation(type, rect,NextSpriteFlashStateChange(aSprite),0,0, aSprite->Win());
1104 //Scheduling an animation "now" means it will take place at next animation which might
1105 //be the full animation grace period into the future (see KAnimationGrace in server.cpp)
1106 aSprite->Screen()->ScheduleAnimation(type, rect,0,0,0, aSprite->Win());
1110 // Sprite flashing is clamped to half second intervals in relation to the global time.
1111 // For the first half of each second all sprites have the EFlashOn state (visible)
1112 // For the second half of each second all sprites have the EFlashOff state (not visible)
1113 TTimeIntervalMicroSeconds CWsSpriteManager::NextSpriteFlashStateChange(const CWsSpriteBase* aSprite) const
1115 const TTimeIntervalMicroSeconds remainder = aSprite->Screen()->Now().DateTime().MicroSecond();
1116 return CalculateTimeToNextFlash(remainder);
1119 TTimeIntervalMicroSeconds CWsSpriteManager::NextCursorFlashStateChange() const
1121 const TTimeIntervalMicroSeconds remainder = CWsTop::CurrentFocusScreen()->Now().DateTime().MicroSecond();
1122 return CalculateTimeToNextFlash(remainder);
1125 TTimeIntervalMicroSeconds CWsSpriteManager::CalculateTimeToNextFlash(TTimeIntervalMicroSeconds aTime) const
1127 TInt64 nextStateChange;
1128 if(aTime<KFlashHalfSecond)
1129 nextStateChange=KFlashHalfSecond-aTime.Int64();
1131 nextStateChange=KFlashHalfSecond - (aTime.Int64() - KFlashHalfSecond);
1132 ASSERT(nextStateChange > 0);
1133 return TTimeIntervalMicroSeconds(nextStateChange);
1136 TFlashState CWsSpriteManager::CurrentSpriteFlashState(const CWsSpriteBase* aSprite) const
1138 return (aSprite->Screen()->Now().DateTime().MicroSecond()<KFlashHalfSecond)?EFlashOn:EFlashOff;
1141 void CWsSpriteManager::CalcFloatingSpriteRgn( TRegion& aResultRgn, const TRect& aDefaultRect )
1144 for (TInt i=0 ; i<iFloatingSprites.Count() && !aResultRgn.CheckError(); i++)
1146 CWsSpriteBase* sprite = iFloatingSprites[i];
1147 if ( sprite->CanBeSeen() && ( sprite->IsActive() || sprite->IsActivated() ) )
1149 aResultRgn.AddRect( sprite->Rect() );
1153 if ( aResultRgn.CheckError() && iFloatingSprites.Count() > 0 )
1156 aResultRgn.AddRect( aDefaultRect );
1160 void CWsSpriteManager::SendState(MWsWindowTreeObserver& aWindowTreeObserver) const
1162 for(TInt i=iFloatingSprites.Count()-1; i>=0; i--)
1164 CWsSpriteBase* sprite = iFloatingSprites[i];
1165 sprite->SendState(aWindowTreeObserver);