graphicscomposition/surfaceupdate/tsrc/tcompositionbackend.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:36:49 +0300
changeset 183 6a1564a2f3e6
parent 0 5d03bc08d59c
permissions -rw-r--r--
Revision: 201037 Kit: 201037

// Copyright (c) 2006-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:
//

/**
 @file
 @test
 @internalComponent - Internal Symbian test code 
*/

#include <e32std.h>
#include "tcompositionbackend.h"
#include <graphics/suerror.h>

const TInt KNotificationsAtTime = 10; //how many notifications could be processed at a time, varies from 1...

CTContentUpdateReceiver::CTContentUpdateReceiver(TInt aScreen) :
	iScreen(aScreen), iVisible(ETrue)
	{
	RThread thread;
	iReceiverThreadId = thread.Id();
	}

CTContentUpdateReceiver::~CTContentUpdateReceiver()
	{
	if(iPeriodic)
		iPeriodic->Cancel();
	delete iPeriodic;
	iLock.Close();
	iPriorityLock.Close();
	}

void CTContentUpdateReceiver::ConstructL()
	{
	TCallBack callback(CallBack);
	callback.iPtr = this;
	User::LeaveIfError(iLock.CreateLocal());
	User::LeaveIfError(iPriorityLock.CreateLocal(0));
    iPeriodic= CPeriodic::NewL(CPeriodic::EPriorityStandard);
    iPeriodic->Start(TTimeIntervalMicroSeconds32(0),TTimeIntervalMicroSeconds32(KCompositionInterval), callback);
	}

CTContentUpdateReceiver* CTContentUpdateReceiver::NewL(TInt aScreen)
	{
	CTContentUpdateReceiver* receiver = new (ELeave) CTContentUpdateReceiver(aScreen);
	CleanupStack::PushL(receiver);
	receiver->ConstructL();
	CleanupStack::Pop();
	return receiver;  
	}

TInt    CTContentUpdateReceiver::Extension_(TUint aExtensionId, TAny*& aRetIface, TAny* a1)
    {
    switch (aExtensionId)
        {
        case MCompositionSurfaceUpdate::ETypeId:
            aRetIface= static_cast<MCompositionSurfaceUpdate*>(this);
            return KErrNone;

        default:    ;
        }
    return CExtensionContainer::Extension_(aExtensionId,aRetIface,a1);
    }

TInt CTContentUpdateReceiver::CallBack(TAny *aAny)
	{
	return (static_cast <CTContentUpdateReceiver*> (aAny))->CheckNewNotifications();
	}

void CTContentUpdateReceiver::Stop()
	{
    iLock.Wait();
	iStop = ETrue;
    iLock.Signal();
	}

EXPORT_C void CTContentUpdateReceiver::SetVisible(TBool aVisible)
    {
    iLock.Wait();
    iVisible = aVisible;
    iLock.Signal();
    }

TInt CTContentUpdateReceiver::CheckNewNotifications()
	{
	iLock.Wait();
 	if(iStop && (iNumberElements <= 0))
		{
	    iLock.Signal();
		CActiveScheduler::Stop();
		return 0;//the return value is irrelevant for CPeriodic function
		}
	if(iSetInternalPriority)
		{
		TRAPD(res, DoSetInternalPriorityL());
	    iLock.Signal();
		__ASSERT_ALWAYS(res ==KErrNone, User::Panic(_L("CheckNewNotifications"), KErrGeneral));
		return 0;//the return value is irrelevant for CPeriodic function
		}	
	TInt index = 0;	
	RThread thread;
	TInt res = thread.Open(iThreadId);
	__ASSERT_ALWAYS(res ==KErrNone, User::Panic(_L("CheckNewNotifications"), KErrGeneral));

		//we will check only one limited amount of requests at the time
	for(TInt iteration = 0; (iNumberElements > index) && (iteration < KNotificationsAtTime); iteration++)
		{
		if(iArray[index].iType == EReqDisplayed)
			{
			*(iArray[index].iTimeStamp) = User::FastCounter();
			if(iCompositionOrder)
				{
				iCompositionOrder->SetOrder(EOrderComposition);
				}
			}
		else if(iArray[index].iType == EReqDisplayedXTimes)
			{
			iArray[index].iDisplayedXTimes--;
			if(iArray[index].iDisplayedXTimes > 0)
				{
				index++;
				continue;
				}
			}
		TRequestStatus* status = iArray[index].iStatus;
		res = iVisible ? KErrNone : KErrNotVisible;
		Remove(index);
		thread.RequestComplete(status, res);
		}
	thread.Close();	
    iLock.Signal();
	return 0;//the return value is irrelevant for CPeriodic function
	}

void CTContentUpdateReceiver::DoSetInternalPriorityL()
	{
	RThread thread;
	User::LeaveIfError(thread.Open(iReceiverThreadId));
	thread.SetPriority(iInternalPriority);
	thread.Close();
	TInt compositionInterval = KCompositionInterval;
	CPeriodic::TPriority priority = CPeriodic::EPriorityStandard;
	if(iInternalPriority < EPriorityNormal)
		{
		priority = CPeriodic::EPriorityIdle;
		compositionInterval = KCompositionIntervalLong;
		}
	else if (iInternalPriority > EPriorityNormal)
		{
		priority = CPeriodic::EPriorityHigh;
		compositionInterval = KCompositionIntervalShort;
		}

	TCallBack callback(CallBack);
	callback.iPtr = this;
	iPeriodic->Cancel();
	delete iPeriodic;
	iPeriodic= CPeriodic::NewL(priority);
	iPeriodic->Start(TTimeIntervalMicroSeconds32(compositionInterval),TTimeIntervalMicroSeconds32(compositionInterval), callback);
	iSetInternalPriority = EFalse;
	iPriorityLock.Signal();
	}

EXPORT_C TInt CTContentUpdateReceiver::SetInternalPriority(TThreadPriority aInternalPriority)
	{
	iLock.Wait();
	iInternalPriority = aInternalPriority;
	iSetInternalPriority = ETrue;
    iLock.Signal();
	
    //wait for the priority changes takes place
    iPriorityLock.Wait();
	return KErrNone;
	}

void CTContentUpdateReceiver::ContentUpdated(const TSurfaceId& aId, 
				TInt aBuffer, 
				const TRegion* aRegion, 
				TRequestStatus* aStatusAvailable, 
				TRequestStatus* aStatusDisplayed, TUint32* aTimeStamp, 
				TRequestStatus* aStatusDisplayedXTimes, TInt* aDisplayedXTimes)
	{
	(TAny)&aId;
	(TAny)aBuffer;
	(TAny)aRegion;
	
	iLock.Wait();
	if(iStop)
		{
		if(aStatusAvailable)
			{
			User::RequestComplete(aStatusAvailable, KErrDied);
			}
		if(aStatusDisplayed)
			{
			User::RequestComplete(aStatusDisplayed, KErrDied);
			}
		if(aStatusDisplayedXTimes)
			{
			User::RequestComplete(aStatusDisplayedXTimes, KErrDied);
			}
	    iLock.Signal();
		return;
		}
	
	RThread thread;
	iThreadId = thread.Id();
	
	if(aStatusAvailable)
		{
		Add(aStatusAvailable, EReqAvailable);
		}
	if(aStatusDisplayed)
		{
		Add(aStatusDisplayed, EReqDisplayed, 0, aTimeStamp);
		}
	if(aStatusDisplayedXTimes)
		{
		Add(aStatusDisplayedXTimes, EReqDisplayedXTimes, *aDisplayedXTimes);
		}
    iLock.Signal();
	}

/** 
   Add notification to the list. The function is called from the SUS thread.
   The client of this API must use a lock mechanizm to preserve data integrity.
*/
TInt CTContentUpdateReceiver::Add(TRequestStatus *aStatus, RequestType aType, 
			TInt aDisplayedXTimes, TUint32* aTimeStamp)
	{
 	TInt index = iNumberElements;
	TInt max = sizeof(iArray) / sizeof(iArray[0]) - 1;
	if(index >= max)
		return KErrOverflow;
	
	iArray[index].iStatus = aStatus;
	iArray[index].iType = aType;
	iArray[index].iDisplayedXTimes = aDisplayedXTimes;
	iArray[index].iTimeStamp = aTimeStamp;
	
	iNumberElements++;
	return KErrNone;
	}

/** 
   Remove notification from the list.
   The function is called from the backend thread. 
   The client of this API must use a lock mechanizm to preserve data integrity.
*/
void CTContentUpdateReceiver::Remove(TInt aIndex) 
	{
	TInt max = sizeof(iArray) / sizeof(iArray[0]) - 1;
	if((aIndex < 0) || (aIndex >= max))
			return;
	
	iNumberElements--;
	if(aIndex < iNumberElements)
		{
		Mem::Move(&iArray[aIndex], &iArray[aIndex + 1], (iNumberElements - aIndex) * sizeof(RequestObject));
		iArray[iNumberElements].iType= EReqEmpty;
		}
	else
		{
		iArray[aIndex].iType = EReqEmpty;
		}	
	}
	
TInt CTContentUpdateReceiver::ThreadFunction(TAny* aAny)
	{
	  // get clean-up stack
	CTrapCleanup* cleanup=CTrapCleanup::New();
	RThread thread;
	_LIT(KTestReceiver, "TestReceiver");
	__ASSERT_ALWAYS(cleanup!=NULL, thread.Panic( KTestReceiver, KErrNoMemory));
	
	  // create an active scheduler and server
	CActiveScheduler *pA = new CActiveScheduler;
	__ASSERT_ALWAYS(pA != NULL, thread.Panic( KTestReceiver, KErrNoMemory));

	  //Install the active scheduler
	CActiveScheduler::Install(pA);

	CTContentUpdateReceiver *pCB = NULL;
	TInt screen = * (static_cast <TInt*> (aAny));
	TRAPD(err, pCB = CTContentUpdateReceiver::NewL(screen));
	__ASSERT_ALWAYS(err == KErrNone, thread.Panic( KTestReceiver, err));
	
 	*(static_cast <CTContentUpdateReceiver**> (aAny)) = pCB;
    
      // Let everyone know that we are ready to
      // deal with requests.
	RThread::Rendezvous(KErrNone);
	  // And start fielding requests from client(s).
	CActiveScheduler::Start();

     // Tidy up... 	
	delete pCB;
	delete pA;
	delete cleanup; 
	
	return KErrNone;
	}

_LIT(KMaskBackend, "CompositionBackend_%d");
const TUint KDefaultHeapSize=0x10000;

EXPORT_C TInt StartTestUpdateReceiver(CTContentUpdateReceiver*& aReceiver, TInt aScreen)
	{
	RThread compositionThread;
	TInt res = KErrGeneral;
	TBuf<64> contentUpdateReceiverThreadName;
	TBuf<64> contentUpdateReceiverThreadMask;
	
	// Guarantee uniqueness of thread name by using timestamp
	TTime tm;
	TBuf<32> timeStamp;
	tm.UniversalTime();
	TRAP(res, tm.FormatL(timeStamp, _L("_%H%T%S%C")));
	if(res != KErrNone)
		{
		return res;
		}

	contentUpdateReceiverThreadName.Format(KMaskBackend, aScreen);
	contentUpdateReceiverThreadName.Append(timeStamp);
	contentUpdateReceiverThreadMask = contentUpdateReceiverThreadName;
	contentUpdateReceiverThreadMask.Insert(0, _L("*"));
	TFindThread findThread(contentUpdateReceiverThreadMask);
	TFullName name;
	  // Need to check that the thread exists.
	if (findThread.Next(name)!=KErrNone)
		{
		aReceiver = reinterpret_cast <CTContentUpdateReceiver*> (aScreen);
		
		  // Create the thread for the server.
		res = compositionThread.Create(contentUpdateReceiverThreadName,
			CTContentUpdateReceiver::ThreadFunction,
			KDefaultStackSize,
			KDefaultHeapSize,
			KDefaultHeapSize,
			(TAny*) &aReceiver
			);
			
          // The thread has been created OK so get it started - however
          // we need to make sure that it has started before we continue.
		if (res==KErrNone)
			{
			TRequestStatus rendezvousStatus;
			compositionThread.SetPriority(EPriorityNormal);
			compositionThread.Rendezvous(rendezvousStatus);
			compositionThread.Resume();
			User::WaitForRequest(rendezvousStatus);
			res = rendezvousStatus.Int();
			}
		}
		compositionThread.Close();
		return res;
	}

EXPORT_C void CloseTestUpdateReceiver(CTContentUpdateReceiver* aReceiver)
	{
	if(!aReceiver)
		return;

	TBuf<64> contentUpdateReceiverThreadName;
	contentUpdateReceiverThreadName.Format(KMaskBackend, aReceiver->Screen());
	TBuf<64> contentUpdateReceiverThreadMask;
	contentUpdateReceiverThreadMask = contentUpdateReceiverThreadName;
	contentUpdateReceiverThreadMask.Insert(0, _L("*"));
	contentUpdateReceiverThreadMask.Append('*');
	TFindThread findThread(contentUpdateReceiverThreadMask);
	TFullName name;
	RThread thread;
	if((findThread.Next(name)!=KErrNone) ||
		(thread.Open(findThread) != KErrNone))
		{
		thread.Close();
		return;
		}
	TRequestStatus status; 
	thread.Logon(status);
	if(aReceiver)
		aReceiver->Stop();
	User::WaitForRequest(status);
	thread.Close();
	}