windowing/windowserver/nga/SERVER/SERVER.CPP
changeset 0 5d03bc08d59c
child 26 15986eb6c500
child 110 7f25ef56562d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/SERVER/SERVER.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,956 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Window server 'server' class
+// 
+//
+
+#include "server.h"
+#include "panics.h"
+#include "wstop.h"
+#include "EVENT.H"
+#include <Graphics/WSGRAPHICDRAWERINTERFACE.H>
+#include <bitdraw.h>
+#include <hal.h>
+#include "inifile.h"
+#include "wspluginmanager.h"
+#include "graphics/windowserverconstants.h"
+
+GLREF_D CDebugLogBase *wsDebugLog;
+
+const TUint KRangeCount = 1; 
+// We use a lot of 64 bit time calculations, but a periodic can only cope with signed 32 bit times
+// which gives them a limit of about 35 minutes.
+// Fortunately, our animtions are safe if redrawn early.  Every half an hour isn't going to hurt.
+const TTimeIntervalMicroSeconds KHalfHour = 30 * 60 * 1000 * 1000;
+
+const TInt KWsServRanges[KRangeCount] = 
+	{	
+	0
+	};
+
+const TUint8 KElementsIndex[KRangeCount] =
+	{
+	CPolicyServer::EAlwaysPass,		
+	};
+
+const CPolicyServer::TPolicyElement KPolicyElements[] = 
+	{ 
+	{_INIT_SECURITY_POLICY_C1(ECapabilityPowerMgmt), CPolicyServer::EFailClient}, 
+	{_INIT_SECURITY_POLICY_C1(ECapabilitySwEvent), CPolicyServer::EFailClient}, 
+	{_INIT_SECURITY_POLICY_C1(ECapabilityWriteDeviceData), CPolicyServer::EFailClient} 
+	};
+
+const CPolicyServer::TPolicy KWsServPolicy =
+	{
+	CPolicyServer::EAlwaysPass, 
+	KRangeCount,
+	KWsServRanges,
+	KElementsIndex,
+	KPolicyElements 	
+	};
+ 	
+// CWindowServer::CDefaultAnimationScheduler \\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+class CWindowServer::CDefaultAnimationScheduler: public CBase, public MWsAnimationScheduler
+	{
+	// Associates a screen number with a CActiveSchedulerWait intance. This is used to
+	// achieve synchronous update completion on a specific screen.
+	class CScreenUpdateWait : public CActiveSchedulerWait
+		{
+		public:
+			CScreenUpdateWait(TInt aScreenNumber) : iScreenNumber (aScreenNumber) {}
+			TInt iScreenNumber;	
+		};
+	
+	struct TScreenUpdateDetails
+		{
+		CWindowServer::CDefaultAnimationScheduler* iScheduler;
+		TInt  iScreenNumber;
+		};
+	
+	struct TSchedule
+		{
+		MWsScreen* iScreen; // used as a unique index, searching with FindInUnsignedKeyOrder
+		TInt  iScreenNumber;
+		TBool iScheduled;
+		TTime iWhen;
+		TBool iRedraw;
+		};
+public:
+	enum TInactivityBehaviour
+		{
+		EStopAnimation,
+		EStopAllDrawing,
+		EIgnore,
+		};
+	class CScreenState;
+
+	CDefaultAnimationScheduler(MWsGraphicDrawerEnvironment& aEnv);
+	~CDefaultAnimationScheduler();
+	void ConstructL();		//LeaveScan:  member of nested class declaration
+	// implementing MWsAnimationScheduler
+	void ScheduleAnimation(MWsScreen& aScreen,const TTime& aWhen);
+	void UnscheduleAnimation(MWsScreen& aScreen);
+	void Invalidate(const TGraphicDrawerId& aId);
+	void OnInactive();
+	void OnActive();
+	void ScheduleRedraw(MWsScreen& aScreen,const TTime& aWhen);
+	void DoRedrawNow(MWsScreen& aScreen);
+private:
+	static TBool OnIdleCallBack(TAny* aAny);
+	void ScheduleUpdate (TInt aScreenNumber, TBool aForce);
+	void OnIdleCallBack(TBool aForce);
+	static TBool InvokeDueAnimation(TAny* aAny);
+	void RedrawAllInvalidatedRegions (TInt aScreen);
+	TSchedule* GetScheduledScreenUpdate(TInt aScreen);
+	void InvokeDueAnimation(TInt aScreen);
+	void ProcessUpdateCompletion (TInt aScreenNumber);
+	TInt ScreenNumber(MWsScreen& aScreen) const;
+	TTimeIntervalMicroSeconds GetDueDelta (TBool aForceRedraw, TSchedule* aScheduledUpdate);
+private:
+	RPointerArray<CScreenUpdateWait> iRedrawWaitLoop; 
+	RPointerArray<CScreenState> iScreenState;
+	MWsGraphicDrawerEnvironment& iEnv;
+	static const TInt64 KRedrawGrace;
+	static const TInt64 KAnimationGrace;
+	CAsyncCallBack* iIdleInitiator;
+	TBool iInRedrawNow;
+	RArray<TSchedule> iSchedule;
+	TBool iInactive;
+	TBool iInactiveDraws;
+	TBool iRedrawScheduled;
+	TInt64 iRedrawGracePeriod;
+	TInt64 iAnimationGracePeriod;
+	TInactivityBehaviour iInactivityBehaviour;
+	};
+
+class CWindowServer::CDefaultAnimationScheduler::CScreenState : public CActive
+	{
+public:
+	static CScreenState* NewL (CDefaultAnimationScheduler* aScheduler, TInt aScreenOrdinal);
+	~CScreenState();
+	void SetActive ();
+	
+	CPeriodic* iUpdateOn;
+	TTime      iExpectedTickTime;
+	TScreenUpdateDetails iScreenUpdateDetails;
+	RArray<TGraphicDrawerId> iInvalidated;
+	TBool 		iInvalidateAll;
+	
+private:
+	CScreenState (CDefaultAnimationScheduler* aScheduler, TInt aScreenOrdinal);
+	void ConstructL ();
+	
+	void RunL();
+	void DoCancel() 
+		{
+		TRequestStatus* tmpTRS = &iStatus;
+		User::RequestComplete(tmpTRS, KErrNone);
+		};
+	};
+
+// If using the default animation scheduler on a device, these two numbers may be worth tweaking in the inifile
+// However, both are maximum periods - wserv will go faster than either if nothing else is using the system.
+const TInt64 CWindowServer::CDefaultAnimationScheduler::KRedrawGrace = 0; // do redraws immediately
+const TInt64 CWindowServer::CDefaultAnimationScheduler::KAnimationGrace = 0; // do animation redraws immediately
+	
+CWindowServer::CDefaultAnimationScheduler::CDefaultAnimationScheduler(MWsGraphicDrawerEnvironment& aEnv):
+	iEnv(aEnv), iSchedule(1,_FOFF(TSchedule,iScreen))
+	{
+	}
+
+CWindowServer::CDefaultAnimationScheduler::~CDefaultAnimationScheduler()
+	{
+	iSchedule.Close();
+	delete iIdleInitiator;
+	
+	TInt screenCount = iScreenState.Count();
+	for (TInt ii = 0; ii < screenCount; ii++)
+		delete iScreenState[ii];
+
+	iScreenState.Close();
+
+	// Destroy the redraw wait loops associated each screen, and close
+	// the associated Array objects.
+	TInt waitLoopCount = iRedrawWaitLoop.Count();
+	for (TInt waitLoop = 0; waitLoop < waitLoopCount; waitLoop++)
+		delete iRedrawWaitLoop[waitLoop];
+	iRedrawWaitLoop.Close();
+	}
+	
+void CWindowServer::CDefaultAnimationScheduler::ConstructL()
+	{
+	_LIT(KOnInactive,"ONINACTIVE");
+	_LIT(KStopAnimation,"STOPANIMATION");
+	_LIT(KStopAllDrawing,"STOPALLDRAWING");
+	_LIT(KIgnore,"IGNORE");
+	
+	TPtrC inactivityBehaviourString;
+	WsIniFile->FindVar(KOnInactive,inactivityBehaviourString);
+	if(inactivityBehaviourString.CompareF(KStopAnimation)==0)
+		iInactivityBehaviour = EStopAnimation;
+	else if(inactivityBehaviourString.CompareF(KStopAllDrawing)==0)
+		iInactivityBehaviour = EStopAllDrawing;
+	else if(inactivityBehaviourString.CompareF(KIgnore)==0)
+		iInactivityBehaviour = EIgnore;
+		
+	_LIT(KRedrawGracePeriod, "REDRAWGRACEPERIOD");
+	TInt tmp = KRedrawGrace;
+	WsIniFile->FindVar(KRedrawGracePeriod, tmp);
+	iRedrawGracePeriod = tmp;
+	
+	_LIT(KAnimationGracePeriod, "ANIMATIONGRACEPERIOD");
+	tmp = KAnimationGrace;
+	WsIniFile->FindVar(KAnimationGracePeriod, tmp);
+	iAnimationGracePeriod = tmp;
+	
+	iIdleInitiator = new(ELeave) CAsyncCallBack(TCallBack(OnIdleCallBack,this),EWsGraphicAnimateAwaitIdlePriority);
+	
+	TInt screenCount;
+	User::LeaveIfError(HAL::Get( HAL::EDisplayNumberOfScreens, screenCount)); 
+	for (TInt i = 0; i < screenCount; i++)
+		{
+		CScreenState* screenState = CScreenState::NewL (this, i);
+		CleanupStack::PushL(screenState);
+		iScreenState.AppendL (screenState);
+		CleanupStack::Pop(screenState);
+		}
+		
+	
+	// Ensure that the wait loop array has some allocated slots, making it highly 
+	// unlikely that Append() will fail due to OOM.
+	iRedrawWaitLoop.ReserveL (8);
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::Invalidate(const TGraphicDrawerId& aId)
+	{
+	const TInt screenCount = iEnv.ScreenCount();
+	for(TInt ii = 0; ii < screenCount; ii++)
+		{
+		CScreenState* screenState = iScreenState[ii];
+		if(!screenState->iInvalidateAll)
+			{
+			switch(screenState->iInvalidated.InsertInOrder(aId,TLinearOrder<TGraphicDrawerId>(TGraphicDrawerId::Compare)))
+				{
+				case KErrNone:
+				case KErrAlreadyExists:
+					break;
+				default:
+					screenState->iInvalidateAll = ETrue;
+					screenState->iInvalidated.Reset();
+				}
+			}
+		}
+	iIdleInitiator->CallBack();
+	}
+
+CWindowServer::CDefaultAnimationScheduler::CScreenState::CScreenState (CDefaultAnimationScheduler* aScheduler, TInt aScreenNumber):
+	CActive(EComposeCompletePriority)
+	{
+	iScreenUpdateDetails.iScheduler = aScheduler;
+	iScreenUpdateDetails.iScreenNumber = aScreenNumber;
+	}
+
+CWindowServer::CDefaultAnimationScheduler::CScreenState* 
+CWindowServer::CDefaultAnimationScheduler::CScreenState::NewL (CDefaultAnimationScheduler* aScheduler, TInt aScreenOrdinal)
+	{
+	CScreenState* self = new(ELeave)CScreenState(aScheduler, aScreenOrdinal);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;	
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::CScreenState::ConstructL ()
+	{
+	iUpdateOn = CPeriodic::NewL(EComposeCompletePriority);
+	CActiveScheduler::Add(this);
+	}
+
+CWindowServer::CDefaultAnimationScheduler::CScreenState::~CScreenState()
+	{
+	CActive::Cancel();
+	iInvalidated.Close();
+	delete iUpdateOn;
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::CScreenState::SetActive()
+	{
+	CActive::SetActive ();
+	}
+	
+/** 
+Invoked when the rendering pipline signals that it is ready to recieve updated.
+*/
+void CWindowServer::CDefaultAnimationScheduler::CScreenState::RunL() 
+	{
+	iScreenUpdateDetails.iScheduler->ProcessUpdateCompletion (iScreenUpdateDetails.iScreenNumber);
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::ProcessUpdateCompletion (TInt aScreenNumber)
+	{
+	// Stop all waitloops related to the specified screen.
+	TInt waitLoopCount = iRedrawWaitLoop.Count();
+	for (TInt waitLoop = 0; waitLoop < waitLoopCount; waitLoop++)
+		if (iRedrawWaitLoop[waitLoop]->IsStarted() && (iRedrawWaitLoop[waitLoop]->iScreenNumber == aScreenNumber))
+			iRedrawWaitLoop[waitLoop]->AsyncStop();
+	
+	// Perform any outstanding redraws on the specified screen.
+	ScheduleUpdate (aScreenNumber, ETrue);
+	}
+
+/**
+Switch to deactivate animation or drawing (based on setting of iInactivityBehaviour).
+See InvokeDueAnimation().
+*/
+void CWindowServer::CDefaultAnimationScheduler::OnInactive()
+	{
+	iInactive = ETrue;
+	}
+
+/**
+Switch to deactivate/activate animation or drawing (based on setting of iInactivityBehaviour).
+See InvokeDueAnimation().
+*/	
+void CWindowServer::CDefaultAnimationScheduler::OnActive()
+	{
+	iInactive = EFalse;
+	if(iInactiveDraws)
+		{
+		iInactiveDraws = EFalse;
+		iIdleInitiator->CallBack();
+		}
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::ScheduleRedraw(MWsScreen& aScreen,const TTime& aWhen)
+	{
+	iRedrawScheduled = ETrue;
+	ScheduleAnimation(aScreen, aWhen);
+	}
+
+/** 
+Given a MWsScreen pointer, return an integer value representing the ordinal position
+of the screen in the Window Server.
+*/
+TInt CWindowServer::CDefaultAnimationScheduler::ScreenNumber(MWsScreen& aScreen) const
+	{
+	TInt numberOfScreens = CWsTop::NumberOfScreens();
+	TInt theScreen;
+	
+	for (theScreen = 0; theScreen < numberOfScreens; theScreen++)
+		if (CWsTop::Screen(theScreen) == &aScreen) 
+			break;
+	
+	WS_ASSERT_DEBUG(theScreen < numberOfScreens, EWsPanicWsGraphic);
+	return theScreen;
+	}
+
+/**
+Perform redraw and return only when completed.
+NOTE: This method uses CActiveSchedulerWait to run a "modal wait loop" while the
+		redraw complete signal is pending. When the signal is recieved, AsyncStop() is
+		invoked on all active wait loops for the signalling screen. 
+*/
+void CWindowServer::CDefaultAnimationScheduler::DoRedrawNow(MWsScreen& aScreen)
+	{	
+	TInt screenNumber = ScreenNumber (aScreen);
+	TInt redrawCount = 0;
+		
+	// redrawCount is the number of times we should wait for redraws to complete.
+	// If a redraw is not currently active then we need to wait (at most) once: for
+	// any outstanding scheduled update to complete.
+	// If a redraw is currently active then we need to wait (at most) twice: once for
+	// the current update to complete, and once for any outstanding scheduled update to complete.	
+	if (!iScreenState[screenNumber]->IsActive())
+		{		
+		// No animation in progress, so force a redraw of due updates.
+		ScheduleUpdate(screenNumber, ETrue);
+		
+		// If there is still nothing drawing, set redrawCount to zero to make sure we do not wait.
+		if (!iScreenState[screenNumber]->IsActive())
+			redrawCount = 0;
+		else
+			redrawCount = 1;
+		}
+	else
+		redrawCount = 2;
+	
+	// Wait for the sepecified number of redraws.
+	if (redrawCount)
+		{
+		// Allocate the wait loop on the stack so we are not subject to heap OOM.
+		TBuf8<sizeof (CScreenUpdateWait)> buf;
+		Mem::FillZ(&buf, sizeof (CScreenUpdateWait));
+		CScreenUpdateWait* waitLoop = new (&buf) CScreenUpdateWait(screenNumber);
+		if (iRedrawWaitLoop.Append(waitLoop) == KErrNone)
+			{
+			// Run the active scheduler while updates are active
+			while (redrawCount-- && iScreenState[screenNumber]->IsActive())
+				waitLoop->Start();
+			
+			iRedrawWaitLoop.Remove(iRedrawWaitLoop.Count() - 1);			
+			}
+		waitLoop->~CScreenUpdateWait();
+		}
+	}
+
+/**
+Schedule an update for a specific screen at a given point in time.
+*/ 
+void CWindowServer::CDefaultAnimationScheduler::ScheduleAnimation(MWsScreen& aScreen, const TTime& aWhen)
+	{	
+	TSchedule schedule;
+	schedule.iScreen = &aScreen;
+	schedule.iScheduled = ETrue;
+	schedule.iWhen = aWhen;
+	schedule.iScreenNumber = ScreenNumber (aScreen);
+	schedule.iRedraw = iRedrawScheduled;
+	iRedrawScheduled = EFalse;
+	TBool ok = EFalse;
+	const TInt idx = iSchedule.FindInUnsignedKeyOrder(schedule);
+	if(0 <= idx)
+		{
+		TSchedule& currSchedule=iSchedule[idx];
+		if(currSchedule.iScheduled)
+			{
+			if(currSchedule.iWhen > aWhen)
+				{
+				currSchedule.iWhen = aWhen;
+				}
+			}
+		else
+			{
+			currSchedule = schedule;
+			}
+		ok = ETrue;
+		}
+	else
+		ok = (KErrNone == iSchedule.InsertInUnsignedKeyOrder(schedule));
+
+	if(ok)
+		iIdleInitiator->CallBack();
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::UnscheduleAnimation(MWsScreen& aScreen)
+	{
+	TSchedule schedule;
+	schedule.iScreen = &aScreen;
+	const TInt idx = iSchedule.FindInUnsignedKeyOrder(schedule);
+	if(0 <= idx)
+		iSchedule[idx].iScheduled = EFalse;
+	}
+
+TBool CWindowServer::CDefaultAnimationScheduler::OnIdleCallBack(TAny* aAny)
+	{
+	WS_ASSERT_DEBUG(aAny, EWsPanicWsGraphic);
+	
+	if(aAny)
+		static_cast<CDefaultAnimationScheduler*>(aAny)->OnIdleCallBack(EFalse);
+
+	return EFalse; //ignored by caller
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::OnIdleCallBack(TBool aForce)
+	{
+	const TInt screenCount = iEnv.ScreenCount();
+	for(TInt ii = 0; ii < screenCount; ii++)
+		ScheduleUpdate (ii, aForce);
+	}
+
+
+
+/** 
+@return The number of microseconds (from now) that the specified scheduled update should be run at. This
+takes into account any set grace period and protects the scheduler from entering an infinite loop servicing
+animations with back-to-back frame updates.
+*/
+TTimeIntervalMicroSeconds CWindowServer::CDefaultAnimationScheduler::GetDueDelta (TBool aForceRedraw, TSchedule* aScheduledUpdate)
+	{
+	WS_ASSERT_DEBUG(aScheduledUpdate, EWsPanicWsGraphic);
+	WS_ASSERT_DEBUG(aScheduledUpdate->iScheduled, EWsPanicWsGraphic);
+	
+	TTime now;
+	TInt64 grace = I64LIT(0); 
+	TTimeIntervalMicroSeconds thisUpdateDueIn = I64LIT(0); //Microseconds from now
+	
+	// Only use grace periods if not forcing due updates.
+	if (!aForceRedraw)
+		{
+		if (aScheduledUpdate->iRedraw)
+			grace = iRedrawGracePeriod;
+		else
+			grace = iAnimationGracePeriod;
+		}
+	
+	now.UniversalTime();
+	thisUpdateDueIn = aScheduledUpdate->iWhen.MicroSecondsFrom(now);
+	
+	// Add the grace period if the update is due in less time than the grace period.
+	if (thisUpdateDueIn < grace)
+		thisUpdateDueIn = grace;
+	else if (thisUpdateDueIn > KHalfHour)
+		thisUpdateDueIn = KHalfHour;
+	
+	return thisUpdateDueIn;
+	}
+
+/**
+Schedule an actual screen update at the point in time at which it is due. The due time may be modified by
+this method based on any "grace period" values.
+ 
+@param aScreen		Screen number to update.
+@param aForceRedraw Force redraws that are due. This causes grace periods not to be used.
+*/
+void CWindowServer::CDefaultAnimationScheduler::ScheduleUpdate (TInt aScreenNumber, TBool aForceRedraw)
+	{	
+	// Schedule updates for any invalidated regions.
+	RedrawAllInvalidatedRegions (aScreenNumber);
+	
+	TSchedule* scheduledUpdate = GetScheduledScreenUpdate(aScreenNumber);
+	if (scheduledUpdate)
+		{
+		WS_ASSERT_DEBUG(scheduledUpdate->iScheduled, EWsPanicWsGraphic);
+		WS_ASSERT_DEBUG(aScreenNumber < iScreenState.Count(), EWsPanicWsGraphic);
+		
+		CScreenState& screenState = *iScreenState[aScreenNumber];
+				
+		// Initiate redraw if scheduled and not currently updating the display.
+		if(!screenState.IsActive())
+			{
+			TTimeIntervalMicroSeconds thisUpdateDueIn =	
+				GetDueDelta (aForceRedraw, scheduledUpdate);
+			
+			// Reschedule any preexisting update if this one is due earlier.
+			// If this update is not due earlier than a preexisting update then 
+			// there is nothing to do - just let the pending update occur.
+			TTime now;
+			now.UniversalTime();
+			TBool performUpdate = ETrue;
+			if(screenState.iUpdateOn->IsActive())
+				{
+				if (thisUpdateDueIn < screenState.iExpectedTickTime.MicroSecondsFrom(now))
+					screenState.iUpdateOn->Cancel();
+				else
+					performUpdate = EFalse;
+				}
+			
+			if (performUpdate)
+				{
+				if (thisUpdateDueIn.Int64() == 0) // Perform an immediate update if we are due.
+					{
+					screenState.iExpectedTickTime = now;
+					InvokeDueAnimation(aScreenNumber);
+					}
+				else // Schedule the tick at the appropriate time.
+					{
+					WS_ASSERT_DEBUG(thisUpdateDueIn.Int64() > 0, EWsPanicWsGraphic);
+					screenState.iExpectedTickTime = now + thisUpdateDueIn;
+					screenState.iUpdateOn->Start(thisUpdateDueIn.Int64(),0,TCallBack(InvokeDueAnimation, &screenState.iScreenUpdateDetails));
+					}
+				}
+			}
+		}
+	}
+
+/**
+@return 	A pointer to the scheduled update details currently associated with the specified screen.
+			If there is no scheduled update then NULL is returned.
+@note 		There is only ever one scheduled update per screen.
+*/
+CWindowServer::CDefaultAnimationScheduler::TSchedule* CWindowServer::CDefaultAnimationScheduler::GetScheduledScreenUpdate(TInt aScreenNumber)
+	{
+	TSchedule* result = NULL;
+	const TInt count = iSchedule.Count();
+	for(TInt ii = 0; ii < count; ii++)
+		{
+		if (iSchedule[ii].iScreenNumber == aScreenNumber)
+			{
+			if (iSchedule[ii].iScheduled)
+				result = &iSchedule[ii];
+			break;
+			}
+		}
+	
+	return result;
+	}
+
+/**
+Redraw invalidated graphic IDs. If invalid regions exist, this will cause ScheduleRedraw() to be invoked.
+*/ 
+void CWindowServer::CDefaultAnimationScheduler::RedrawAllInvalidatedRegions (TInt aScreen)
+	{	
+	WS_ASSERT_DEBUG(iScreenState.Count() > aScreen, EWsPanicWsGraphic);
+	
+	CScreenState& screenState = *iScreenState[aScreen];
+	if(screenState.iInvalidateAll || screenState.iInvalidated.Count())
+		{		
+		const TArray<TGraphicDrawerId> invalidArray = screenState.iInvalidated.Array();
+		MWsScreen* screen = iEnv.Screen(aScreen);
+		WS_ASSERT_DEBUG(screen, EWsPanicWsGraphic);
+		if(screen)
+			{
+			if(screenState.iInvalidateAll)
+				Redraw(*screen);
+			else
+				RedrawInvalid(*screen, screenState.iInvalidated.Array());
+			}
+		screenState.iInvalidateAll = EFalse;
+		}
+	screenState.iInvalidated.Reset();
+	}
+	
+TBool CWindowServer::CDefaultAnimationScheduler::InvokeDueAnimation(TAny* aAny)
+	{
+	WS_ASSERT_DEBUG(aAny, EWsPanicWsGraphic);
+	TScreenUpdateDetails* args = reinterpret_cast<TScreenUpdateDetails*>(aAny);
+	if(args)
+		args->iScheduler->InvokeDueAnimation (args->iScreenNumber);
+
+	return EFalse;
+	}
+
+void CWindowServer::CDefaultAnimationScheduler::InvokeDueAnimation(TInt aScreen)
+	{
+	WS_ASSERT_DEBUG(aScreen < iScreenState.Count(), EWsPanicWsGraphic);
+	CScreenState& screenState = *iScreenState[aScreen];
+	WS_ASSERT_DEBUG(!screenState.IsActive(), EWsPanicWsGraphic);
+
+	// All updates are driven through ScheduleRedraw() and ScheduleAnimation().
+	screenState.iUpdateOn->Cancel();
+	
+	TSchedule* scheduledUpdate = GetScheduledScreenUpdate(aScreen);	
+	if (scheduledUpdate)
+		{
+		WS_ASSERT_DEBUG(scheduledUpdate->iScheduled, EWsPanicWsGraphic);
+		
+		// Honour any flags that indicate we should not redraw. 
+		switch(iInactivityBehaviour)
+			{
+			case EStopAnimation :
+				// Stop server side drawing. Only the client may redraw if iInactive is set. 
+				if(iInactive && !scheduledUpdate->iRedraw)
+					{
+					iInactiveDraws = ETrue;
+					return;
+					}
+				break;
+			case EStopAllDrawing :
+				// Stop both client and server side drawing.
+				if(iInactive) 
+					{
+					iInactiveDraws = ETrue;
+					return;
+					}
+				break;
+			case EIgnore :
+				break;
+			default :
+				WS_ASSERT_DEBUG(EFalse, EWsPanicWsGraphic);
+				break;
+			}
+	
+		scheduledUpdate->iScheduled = EFalse;
+		screenState.SetActive();
+		Animate(*scheduledUpdate->iScreen, &(screenState.iStatus));
+		}
+	}
+
+// CWindowServer::CServer \\\\\\\\\\\\\\\\\\\\\\
+
+class CWindowServer::CServer : public CPolicyServer
+	{
+public:
+	static CServer* NewL()
+		{
+		return new(ELeave) CServer;
+		}
+	void StartL()
+		{
+		CPolicyServer::StartL(KWSERVServerName);
+		}
+	TInt SessionCount()
+		{
+		iSessionIter.SetToFirst();
+		TInt count=0;
+		while(iSessionIter++)
+			++count;
+		return(count);
+		}
+
+public: //from CPolicyServer
+	/** Creates a new client for this server. */
+	CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const
+		{
+		TVersion v(KWservMajorVersionNumber, KWservMinorVersionNumber, KWservBuildVersionNumber);
+		if (User::QueryVersionSupported(v, aVersion)==EFalse)
+			User::Leave(KErrNotSupported);
+		RThread thread;
+		User::LeaveIfError(aMessage.Client(thread));
+		return(new(ELeave) CWsClient(thread));
+		}
+private:
+	CServer() : CPolicyServer(EMainServerPriority, KWsServPolicy)
+	{}
+	};
+
+
+// CWindowServer \\\\\\\\\\\\\\\\\\\\\\\\\\\
+
+CWindowServer *CWindowServer::NewL()
+//
+// Create a new CWindowServer.
+//
+	{
+	CWindowServer* self = new(ELeave) CWindowServer();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CWindowServer::CWindowServer()
+//
+// Constructor.
+//
+	{
+	}
+
+CWindowServer::~CWindowServer()
+	{
+	delete iServer;
+
+	iMemoryReleases.Reset();
+	WS_ASSERT_DEBUG(iDrawerMasterIndex.IsEmpty(), EWsPanicWsGraphic);
+	iDrawerMasterIndex.Close();
+	
+	delete iDefaultAnimationScheduler;
+	iDefaultAnimationScheduler = NULL; //might be called from clients during server destruction
+	iCustomAnimationScheduler = NULL; // not owned	
+	}
+	
+void CWindowServer::ConstructL()
+	{
+	iServer = CServer::NewL();
+	CWsTop::PluginManager()->InitializePluginsL(*this); // plugins are loaded and own by CWsTop
+	iDefaultAnimationScheduler = new(ELeave) CDefaultAnimationScheduler(*this);
+	iDefaultAnimationScheduler->ConstructL();
+	RegisterMemoryRelease(this);
+	}
+
+void CWindowServer::StartL()
+	{
+	iServer->StartL();
+	}
+
+void CWindowServer::SetPinClientDescriptors(TBool aPin)
+	{
+	iServer->SetPinClientDescriptors(aPin);
+	}
+
+TInt CWindowServer::SessionCount()
+	{
+	return iServer->SessionCount();
+	}
+
+const CWsGraphicDrawer* CWindowServer::ResolveGraphic(const TGraphicDrawerId& aId) const
+	{
+	return iDrawerMasterIndex.ResolveGraphic(aId);
+	}
+	
+void CWindowServer::Invalidate(const TGraphicDrawerId& aId)
+	{
+	AnimationScheduler()->Invalidate(aId);
+	}
+	
+TInt CWindowServer::ScreenCount() const
+	{
+	return CWsTop::NumberOfScreens();
+	}
+
+MWsScreen* CWindowServer::Screen(TInt aIndex)
+	{
+	if((aIndex >= 0) && (aIndex < ScreenCount()))
+		{
+		return CWsTop::Screen(aIndex);
+		}
+	return NULL;
+	}
+	
+const MWsScreen* CWindowServer::Screen(TInt aIndex) const
+	{
+	if((aIndex >= 0) && (aIndex < ScreenCount()))
+		{
+		return CWsTop::Screen(aIndex);
+		}
+	return NULL;
+	}
+	
+/**
+Custom Animation Scheduler
+*/
+TBool CWindowServer::SetCustomAnimationScheduler(MWsAnimationScheduler* aScheduler)
+	{
+	if(!iCustomAnimationScheduler && aScheduler)
+		{
+		iCustomAnimationScheduler = aScheduler;
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+TBool CWindowServer::HasCustomAnimationScheduler() const
+	{
+	return !!iCustomAnimationScheduler;
+	}
+
+TBool CWindowServer::ClearCustomAnimationScheduler(MWsAnimationScheduler* aCurrentScheduler)
+	{
+	if(iCustomAnimationScheduler && (iCustomAnimationScheduler == aCurrentScheduler))
+		{
+		iCustomAnimationScheduler = NULL;
+		return ETrue;
+		}
+	return EFalse;
+	}
+	
+MWsAnimationScheduler* CWindowServer::AnimationScheduler()
+	{
+	if(iCustomAnimationScheduler)
+		{
+		return iCustomAnimationScheduler;
+		}
+	return iDefaultAnimationScheduler;
+	}
+
+TInt CWindowServer::RegisterEventHandler(CWsGraphicDrawer* aDrawer, MWsEventHandler* aHandler, TUint32 aEventMask)
+	{
+	if (!aDrawer || !aHandler || aEventMask==0)
+		return KErrArgument;
+	TInt err = TWindowServerEvent::RegisterDrawerHandler(aDrawer, aEventMask);
+	if (err != KErrNone)
+		return err;
+	aDrawer->SetEventHandler(aHandler);
+	return KErrNone;
+	}
+	
+TInt CWindowServer::UnregisterEventHandler(CWsGraphicDrawer* aDrawer)
+	{
+	if (!aDrawer || (aDrawer && !aDrawer->HasEventHandler()))
+		return KErrArgument;
+	TInt err = TWindowServerEvent::UnregisterDrawerHandler(aDrawer);
+	if (err != KErrNone)
+		return err;
+	aDrawer->SetEventHandler(NULL);
+	return KErrNone;
+	}
+	
+TInt CWindowServer::RegisterWsEventHandler(MWsEventHandler* aHandler, TUint32 aEventMask)
+	{
+	if (!aHandler || aEventMask==0)
+		return KErrArgument;
+	return TWindowServerEvent::RegisterWsEventHandler(aHandler, aEventMask);
+	}
+	
+TInt CWindowServer::UnregisterWsEventHandler(MWsEventHandler* aHandler)
+	{
+	return TWindowServerEvent::UnregisterWsEventHandler(aHandler);
+	}
+	
+TAny* CWindowServer::ResolveObjectInterface(TUint aTypeId)
+	{
+	switch(aTypeId)
+		{
+		case MWsActiveSchedulerDebug::EWsObjectInterfaceId:
+			return static_cast<MWsActiveSchedulerDebug*>(CWsActiveScheduler::Static());
+		case MWsIniFile::EWsObjectInterfaceId:
+			return static_cast<MWsIniFile*>(WsIniFile);
+		}
+	
+	if (CWsPluginManager *plugMgr=CWsTop::PluginManager())
+		return plugMgr->ResolveObjectInterface(aTypeId);
+	
+	return NULL;
+	}
+
+void CWindowServer::Log(TInt aPriority,const TDesC &aFmt,TInt aParam)
+	{
+	if (wsDebugLog)
+		{
+		wsDebugLog->MiscMessage(aPriority, aFmt, aParam);
+		}
+	}
+
+// CWsGraphicDrawer master index
+
+TInt CWindowServer::AddGraphicDrawer(CWsGraphicDrawer* aDrawer)
+	{
+	return iDrawerMasterIndex.Add(aDrawer);
+	}
+
+TInt CWindowServer::SwapGraphicDrawer(CWsGraphicDrawer* aDrawer)
+	{
+	return iDrawerMasterIndex.Swap(aDrawer);
+	}
+	
+TInt CWindowServer::RemoveGraphicDrawer(const TGraphicDrawerId& aId)
+	{
+	return iDrawerMasterIndex.Remove(aId);
+	}
+
+TInt CWindowServer::RemoveAllGraphicDrawers(const MWsClient& aOwner)
+	{
+	return iDrawerMasterIndex.RemoveAll(aOwner);
+	}
+
+TInt CWindowServer::RegisterMemoryRelease(MWsMemoryRelease * aMemoryRelease)
+	{
+	return iMemoryReleases.Append(aMemoryRelease);
+	}
+
+void CWindowServer::UnregisterMemoryRelease(MWsMemoryRelease * aMemoryRelease)
+	{
+	for (TInt ii = iMemoryReleases.Count() - 1; ii >= 0; --ii)
+		{
+		if (iMemoryReleases[ii] == aMemoryRelease)
+			{
+			iMemoryReleases.Remove(ii);
+			break;
+			}
+		}
+	}
+
+TBool CWindowServer::ReleaseMemory(TMemoryReleaseLevel aLevel)
+	{
+	return CWsWindow::ReleaseMemory(aLevel);
+	}
+
+TBool CWindowServer::ReleaseMemory()
+	{
+	TBool released = EFalse;
+	for (TInt level = MWsMemoryRelease::ELow; !released && level <= MWsMemoryRelease::EHigh; ++level)
+		{
+		for (TInt ii = iMemoryReleases.Count() - 1; !released && ii >= 0; --ii)
+			{
+			released = iMemoryReleases[ii]->ReleaseMemory(static_cast<TMemoryReleaseLevel>(level));
+			}
+		}
+	return released;
+	}
+
+void CWindowServer::DestroySessionsForShutdown()
+	{
+	delete iServer;
+	iServer = NULL;
+	}
+