diff -r 000000000000 -r 5d03bc08d59c windowing/windowserver/nonnga/SERVER/SERVER.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowing/windowserver/nonnga/SERVER/SERVER.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,900 @@ +// 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 +#include +#include +#include "inifile.h" +#include "wspluginmanager.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 + { +public: + enum TInactivityBehaviour + { + EStopAnimation, + EStopAllDrawing, + EIgnore, + }; + class CKickBack; + 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); + TInt RemoveGraphicDrawer(const TGraphicDrawerId &aId); + +private: + static TBool OnIdleCallBack(TAny* aAny); + void OnIdleCallBack(TBool aForceRedraw); + static TBool OnTickCallBack(TAny* aAny); + void OnTickCallBack(); + static TBool OnKickBack(TAny* aAny); + void OnKickBack(); +private: + MWsGraphicDrawerEnvironment& iEnv; + static const TInt64 KRedrawGrace; + static const TInt64 KAnimationGrace; + static const TInt64 KDsaAnimationGrace; + CAsyncCallBack* iIdleInitiator; + CPeriodic* iTick; + CKickBack* iKickBack; + struct TSchedule + { + MWsScreen* iScreen; // used as a unique index, searching with FindInUnsignedKeyOrder + TBool iSchedule; + TTime iWhen; + TInt iGeneration; + }; + RArray iSchedule; + TInt iGeneration; + RArray iInvalidated; + TBool iInvalidateAll; // if we could not add to iInvalidated, we have to instead redraw everything + TTime iWhenDesired; + TBool iInactive; + TBool iInactiveDraws; + TTime iExpectedTime; + TBool iRedrawScheduled; + TInt64 iRedrawGracePeriod; + TInt64 iAnimationGracePeriod; + TInt64 iDsaAnimationGracePeriod; + TInactivityBehaviour iInactivityBehaviour; + }; + +TInt CWindowServer::CDefaultAnimationScheduler::RemoveGraphicDrawer(const TGraphicDrawerId &aId) + { + TInt index=iInvalidated.Find(aId); + if (index!=KErrNotFound) + iInvalidated.Remove(index); + return index; + } + +class CWindowServer::CDefaultAnimationScheduler::CKickBack: public CActive + { +public: + CKickBack(const TCallBack& aCallBack); + void ConstructL(); + void RequestKickBack(); + ~CKickBack(); +private: + static TInt IdleThreadFunc(TAny* aAny); + void Loop(); + // from CActive + void RunL(); // fires when kicked back by the idle thread + void DoCancel(); +private: + RThread iWservThread; + RThread iIdleThread; + TRequestStatus iIdleStatus; + TCallBack iCallBack; + }; + +CWindowServer::CDefaultAnimationScheduler::CKickBack::CKickBack(const TCallBack& aCallBack) : +CActive(EPriorityNormal), +iCallBack(aCallBack) + { + CActiveScheduler::Add(this); + } + +void CWindowServer::CDefaultAnimationScheduler::CKickBack::ConstructL() + { + _LIT(KIdleThreadName,"NearlyIdleKickBack"); + const TInt KStackSize = 1024; + User::LeaveIfError(iWservThread.Open(iWservThread.Id())); + User::LeaveIfError(iIdleThread.Create(KIdleThreadName(),IdleThreadFunc,KStackSize,NULL,this)); + iIdleThread.SetPriority(EPriorityAbsoluteVeryLow); + iIdleThread.Resume(); + } + +void CWindowServer::CDefaultAnimationScheduler::CKickBack::RequestKickBack() + { + if (!IsActive()) + { + iStatus = KRequestPending; + SetActive(); + TRequestStatus * status = &iIdleStatus; + iIdleThread.RequestComplete(status, KErrNone); + } + } + +void CWindowServer::CDefaultAnimationScheduler::CKickBack::Loop() + { + FOREVER + { + // This is used here for performance reasons. + User::WaitForRequest(iIdleStatus); + iIdleStatus = KRequestPending; + if (IsActive()&& (iStatus == KRequestPending)) + { + TRequestStatus * status = &iStatus; + iWservThread.RequestComplete(status,KErrNone); + } + } + } + +void CWindowServer::CDefaultAnimationScheduler::CKickBack::RunL() + { + iCallBack.CallBack(); + } + +void CWindowServer::CDefaultAnimationScheduler::CKickBack::DoCancel() + { + } + +CWindowServer::CDefaultAnimationScheduler::CKickBack::~CKickBack() + { + Cancel(); + iWservThread.Close(); + iIdleThread.Kill(0); + iIdleThread.Close(); + } + +TInt CWindowServer::CDefaultAnimationScheduler::CKickBack::IdleThreadFunc(TAny* aAny) + { + CKickBack* owner = reinterpret_cast(aAny); + ASSERT(owner); + if(owner) + { + owner->Loop(); + } + return 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 = 35000; // insist upon 35ms grace for other threads to run when animating +const TInt64 CWindowServer::CDefaultAnimationScheduler::KDsaAnimationGrace = 35000; // insist upon 35ms grace for other threads to run when animating during DSA + +CWindowServer::CDefaultAnimationScheduler::CDefaultAnimationScheduler(MWsGraphicDrawerEnvironment& aEnv): + iEnv(aEnv), iSchedule(1,_FOFF(TSchedule,iScreen)) + { + } + +CWindowServer::CDefaultAnimationScheduler::~CDefaultAnimationScheduler() + { + iSchedule.Close(); + iInvalidated.Close(); + delete iKickBack; + delete iIdleInitiator; + delete iTick; + } + +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; + + _LIT(KDsaAnimationGracePeriod, "DSAANIMATIONGRACEPERIOD"); + tmp = KDsaAnimationGrace; + WsIniFile->FindVar(KDsaAnimationGracePeriod, tmp); + iDsaAnimationGracePeriod = tmp; + + iIdleInitiator = new(ELeave) CAsyncCallBack(TCallBack(OnIdleCallBack,this),EWsGraphicAnimateAwaitIdlePriority); + iTick = CPeriodic::NewL(EWsGraphicAnimatePriority); + + _LIT(KDisableIdleAnimation, "DISABLEIDLEANIMATION"); + if (!WsIniFile->FindVar(KDisableIdleAnimation)) + { + iKickBack = new CKickBack(TCallBack(OnKickBack,this)); + iKickBack->ConstructL(); + } + } + +void CWindowServer::CDefaultAnimationScheduler::Invalidate(const TGraphicDrawerId& aId) + { + if(!iInvalidateAll) + { + switch(iInvalidated.InsertInOrder(aId,TLinearOrder(TGraphicDrawerId::Compare))) + { + case KErrNone: + break; + case KErrAlreadyExists: + break; + default: + iInvalidateAll = ETrue; + iInvalidated.Reset(); + } + } + iIdleInitiator->CallBack(); + } + +void CWindowServer::CDefaultAnimationScheduler::OnInactive() + { + iInactive = ETrue; + } + +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); + } + +void CWindowServer::CDefaultAnimationScheduler::DoRedrawNow(MWsScreen& /*aScreen*/) + { + OnIdleCallBack(ETrue); + } + +void CWindowServer::CDefaultAnimationScheduler::ScheduleAnimation(MWsScreen& aScreen,const TTime& aWhen) + { + TSchedule schedule; + schedule.iScreen = &aScreen; + schedule.iSchedule = ETrue; + schedule.iWhen = aWhen; + schedule.iGeneration = iGeneration; + TBool ok = EFalse; + const TInt idx = iSchedule.FindInUnsignedKeyOrder(schedule); + if(0 <= idx) + { + if(iSchedule[idx].iSchedule) + { + if(iSchedule[idx].iWhen > aWhen) + { + iSchedule[idx].iWhen = aWhen; + } + } + else + { + iSchedule[idx] = schedule; + } + iSchedule[idx].iGeneration = iGeneration; + ok = ETrue; + } + else + { + ok = (KErrNone == iSchedule.InsertInUnsignedKeyOrder(schedule)); + } + if(ok) + { + //If the animation runs at very high rate which exceeds the rate WSERV can + //perform the rendering, it is possible that WSERV animation loop will monopolize + //processor time. + User::After(0); // to yeild from the animation loop + + iIdleInitiator->CallBack(); + } + } + +void CWindowServer::CDefaultAnimationScheduler::UnscheduleAnimation(MWsScreen& aScreen) + { + TSchedule schedule; + schedule.iScreen = &aScreen; + const TInt idx = iSchedule.FindInUnsignedKeyOrder(schedule); + if(0 <= idx) + { + iSchedule[idx].iSchedule = EFalse; + } + } + +TBool CWindowServer::CDefaultAnimationScheduler::OnIdleCallBack(TAny* aAny) + { + CDefaultAnimationScheduler* self = reinterpret_cast(aAny); + ASSERT(self); + if(self) + { + self->OnIdleCallBack(EFalse); + } + return EFalse; //ignored by caller + } + +void CWindowServer::CDefaultAnimationScheduler::OnIdleCallBack(TBool aForceRedraw) + { + TBool wasActive = EFalse; + if (iTick->IsActive()) + { + wasActive = ETrue; + iTick->Cancel(); // stop ticker, as we'll reschedule if necessary + } + if (aForceRedraw) + { + // Don't need to update iExpectedTime as we will not schedule a tick. + // Don't need to update iWhenDesired as we will not schedule a kick-back. + OnTickCallBack(); + return; + } + TBool tick = (iInvalidateAll || iInvalidated.Count()); + TTimeIntervalMicroSeconds next = 0LL; + const TInt count = iSchedule.Count(); + TTime now; + now.UniversalTime(); + if(count) + { + // work out the next wanted tick + TBool animTick = EFalse; + for(TInt i=0; i= 0 && grace > minimum) + grace = minimum; + } + + if (next.Int64() <= 0) + next = 0LL ; // No kickback/tick is needed. Make sure next == default grace period. + + if(next < grace) + { + next = grace; + if (iKickBack) + iKickBack->RequestKickBack(); + } + else if (next > KHalfHour) + next = KHalfHour; + + iExpectedTime=now + next; + if (next.Int64() > 0) + { + iTick->Start(next.Int64(),0,TCallBack(OnTickCallBack,this)); + } + else + { + OnTickCallBack(); // scheduling for 0 doesn't actually execute immediately + } + } + } + +TBool CWindowServer::CDefaultAnimationScheduler::OnKickBack(TAny* aAny) + { + CDefaultAnimationScheduler* self = reinterpret_cast(aAny); + ASSERT(self); + if(self) + { + self->OnKickBack(); + } + return EFalse; //ignored by caller + } + +void CWindowServer::CDefaultAnimationScheduler::OnKickBack() + { + if (iTick->IsActive()) + { + iTick->Cancel(); + TTime now; + now.UniversalTime(); + + TTimeIntervalMicroSeconds fromNow = iWhenDesired.MicroSecondsFrom(now); + + if (fromNow < 0) + { + OnTickCallBack(); + } + else + { + if (fromNow > KHalfHour) + fromNow = KHalfHour; + iTick->Start(fromNow.Int64(),0,TCallBack(OnTickCallBack, this)); + } + } + } + +TBool CWindowServer::CDefaultAnimationScheduler::OnTickCallBack(TAny* aAny) + { + CDefaultAnimationScheduler* self = reinterpret_cast(aAny); + ASSERT(self); + if(self) + { + self->OnTickCallBack(); + } + return EFalse; + } + +void CWindowServer::CDefaultAnimationScheduler::OnTickCallBack() + { + iTick->Cancel(); + + switch(iInactivityBehaviour) + { + case EStopAnimation : + // only client redraws if inactive. server side drawing stopped. + if(iInactive && !iRedrawScheduled) + { + iInactiveDraws = ETrue; + return; + } + break; + case EStopAllDrawing : + // if screen off, stop both client and server side drawing. + if(iInactive) + { + iInactiveDraws = ETrue; + return; + } + break; + case EIgnore : + default : + // ignore inactivity and draw as normal + break; + } + + iRedrawScheduled = EFalse; + + TTime now; + now.UniversalTime(); + CWsActiveScheduler::Static()->AccumReclaimedIdleTime(Max(0LL,now.MicroSecondsFrom(iExpectedTime).Int64())); + + TInt drewCount = 0; + TInt scheduledCount = 0; + /* first redraw any screens that are affected by invalidated graphic IDs */ + if(iInvalidateAll || iInvalidated.Count()) + { + // cancel idle callback if it's already scheduled as we're going to redraw all invalidated + // request at this point and clear invalidated array + if (iIdleInitiator->IsActive()) + iIdleInitiator->Cancel(); + const TArray invalidArray = iInvalidated.Array(); + const TInt screenCount = iEnv.ScreenCount(); + for(TInt i=0; iIsActive(); + if(scheduledCount || !drewCount) + { + TBool rescheduled = EFalse; + for(TInt i=0; iConstructL(); + CleanupStack::Pop(self); + return self; + } + +CWindowServer::CWindowServer() +// +// Constructor. +// + : CPolicyServer(EMainServerPriority,KWsServPolicy) + { + } + +CWindowServer::~CWindowServer() + { + 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 + delete iPluginManager; + } + +void CWindowServer::ConstructL() + { + iPluginManager = CWsPluginManager::NewL(*this); + iDefaultAnimationScheduler = new(ELeave) CDefaultAnimationScheduler(*this); + iDefaultAnimationScheduler->ConstructL(); + RegisterMemoryRelease(this); + } + +/** Creates a new client for this server. */ +CSession2* CWindowServer::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)); + } + +TInt CWindowServer::SessionCount() + { + iSessionIter.SetToFirst(); + TInt count=0; + while(iSessionIter++) + count++; + return(count); + } + +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); + } + +TInt CWindowServer::RegisterRawEventHandler(MEventHandler* aHandler) + { + if (!aHandler) + return KErrArgument; + TRAPD(err, TWindowServerEvent::PotentialEventHandlerL(1)); + if (err != KErrNone) + return err; + TWindowServerEvent::AddEventHandler(aHandler); + return KErrNone; + } + +void CWindowServer::UnregisterRawEventHandler(MEventHandler* aHandler) + { + TWindowServerEvent::RemoveEventHandler(aHandler); + TWindowServerEvent::PotentialEventHandlerL(-1); // can't leave for -1 + } + +void CWindowServer::PostRawEvent(const TRawEvent & aEvent) + { + TWindowServerEvent::ProcessRawEvent(aEvent); + } + +void CWindowServer::PostKeyEvent(const TKeyEvent & aEvent) + { + TWindowServerEvent::ProcessKeyEvent(aEvent, 0); + } + +TAny* CWindowServer::ResolveObjectInterface(TUint aTypeId) + { + switch(aTypeId) + { + case MWsActiveSchedulerDebug::EWsObjectInterfaceId: + return static_cast(CWsActiveScheduler::Static()); + case MWsIniFile::EWsObjectInterfaceId: + return static_cast(WsIniFile); + case MWsRawEventServer::EWsObjectInterfaceId: + return static_cast(this); + } + + if (iPluginManager) + return iPluginManager->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) + { + iDefaultAnimationScheduler->RemoveGraphicDrawer(aId); + return iDrawerMasterIndex.Remove(aId); + } + +TInt CWindowServer::RemoveAllGraphicDrawers(const MWsClient& aOwner) + { + return iDrawerMasterIndex.RemoveAll(aOwner); + } + +CWsPluginManager* CWindowServer::PluginManager() + { + return iPluginManager; + } + +TInt CWindowServer::RegisterMemoryRelease(MWsMemoryRelease * aMemoryRelease) + { + return iMemoryReleases.Append(aMemoryRelease); + } + +void CWindowServer::UnregisterMemoryRelease(MWsMemoryRelease * aMemoryRelease) + { + for (TInt i = iMemoryReleases.Count() - 1; i >= 0; --i) + { + if (iMemoryReleases[i] == aMemoryRelease) + { + iMemoryReleases.Remove(i); + 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 i = iMemoryReleases.Count() - 1; !released && i >= 0; --i) + { + released = iMemoryReleases[i]->ReleaseMemory(static_cast(level)); + } + } + return released; + } +