windowing/windowserver/nonnga/SERVER/Direct.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/Direct.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,613 @@
+// Copyright (c) 2000-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:
+// Direct Screen Access class, to allow the client to draw directly to the screen
+// 
+//
+
+#include <e32base.h>
+#include "Direct.H"
+#include "server.h"
+#include "rootwin.h"
+#include "wstop.h"
+#include "panics.h"
+#include <e32msgqueue.h>
+
+const TInt KMsgQueueLength = 1;
+
+static TBool RegionsMatch(const TRegion & aOne, const TRegion & aTwo);		
+
+
+CDsaMsgQueue* CDsaMsgQueue::NewL(CWsDirectScreenAccess* aDirect)
+	{
+	CDsaMsgQueue* self = new(ELeave)CDsaMsgQueue;
+	CleanupStack::PushL(self);
+	self->ConstructL(aDirect);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CDsaMsgQueue::CDsaMsgQueue()
+{}
+
+CDsaMsgQueue::~CDsaMsgQueue()
+	{
+	delete iAborted;
+	iSendQueue.Close();
+	iRecQueue.Close();
+	}
+
+void CDsaMsgQueue::ConstructL(CWsDirectScreenAccess* aDirect)
+	{
+	iAborted=new(ELeave) CWsAbortDirect(aDirect,this);	
+	}
+
+void CDsaMsgQueue::Cancel()
+	{
+	//purge the queue of data
+	TInt ret = KErrNone;
+	do
+		{
+		TInt data = 0;
+		ret = iRecQueue.Receive(&data,sizeof(TInt));
+		}while(ret == KErrNone);
+	iAborted->Cancel();
+	}
+
+TInt CDsaMsgQueue::Send(TInt aData)
+	{
+	return iSendQueue.Send(&aData,sizeof(TInt));
+	}
+
+TInt CDsaMsgQueue::CreateSendQueue()
+	{
+	if(iSendQueue.Handle() == 0)
+		{
+		return iSendQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess);
+		}
+	else
+		{
+		return 0;
+		}
+	}
+
+TInt CDsaMsgQueue::CreateRecQueue()
+	{
+	if(iRecQueue.Handle() == 0)
+		{
+		return iRecQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess);
+		}
+	else
+		{
+		return 0;
+		}
+	}
+
+RMsgQueueBase* CDsaMsgQueue::SendQueue()
+	{
+	return &iSendQueue;
+	}
+
+RMsgQueueBase* CDsaMsgQueue::RecQueue()
+	{
+	return &iRecQueue;
+	}
+
+void CDsaMsgQueue::Started()
+	{
+	iAborted->Started();
+	}
+	
+void CDsaMsgQueue::Complete()
+	{
+	iAborted->Complete(RDirectScreenAccess::ETerminateCancel);	
+	}
+
+void CDsaMsgQueue::CompleteAbort()
+	{
+	iAborted->Complete(KErrNone);	
+	}
+
+TInt CDsaMsgQueue::ReceiveData()
+	{
+	TInt data = 0;
+	iRecQueue.Receive(&data,sizeof(TInt));
+	return data;
+	}
+
+/*CWsAbortDirect*/
+
+CWsAbortDirect::CWsAbortDirect(CWsDirectScreenAccess* aDirect,CDsaMsgQueue* aParent) : CActive(EDirectAbort), iDirect(aDirect),iParent(aParent)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CWsAbortDirect::~CWsAbortDirect()
+	{
+	Cancel();
+	}
+
+void CWsAbortDirect::Started()
+	{
+	iStatus=KRequestPending;
+	TRequestStatus& status = iStatus;	
+	iParent->RecQueue()->NotifyDataAvailable(status);
+	SetActive();
+	}
+
+void CWsAbortDirect::RunL()
+	{
+	iParent->ReceiveData();
+	iParent->RecQueue()->CancelDataAvailable();
+	iDirect->Aborted();
+	}
+
+void CWsAbortDirect::DoCancel()
+	{
+	iParent->RecQueue()->CancelDataAvailable();
+	if (iStatus==KRequestPending)
+		{
+		Complete(KErrNone);
+		}
+	}
+
+void CWsAbortDirect::Complete(TInt aReason)
+	{
+	if(IsActive())
+		{
+		TRequestStatus* status=&iStatus;
+		RThread().RequestComplete(status,aReason);
+		}
+	}
+
+
+/*CWsDirectScreenAccess*/
+
+CWsDirectScreenAccess* CWsDirectScreenAccess::NewL(CWsClient* aOwner)
+	{
+	CWsDirectScreenAccess* self = new(ELeave) CWsDirectScreenAccess(aOwner);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CWsDirectScreenAccess::~CWsDirectScreenAccess()
+	{
+	DeleteRegionSyncWatchcat();
+	iFrozenRegion.Close();
+	iVisible.Close();
+	if (iStatus!=EDirectStatusTimeNotCreated)
+		{
+		if (iStatus==EDirectStatusRunning)
+			AbortNow();
+		if (iStatus>=EDirectStatusAborted)
+			CorrectScreen();
+		}
+	WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
+	delete iMsgQueue;
+	}
+
+void CWsDirectScreenAccess::ConstructL()
+	{
+	NewObjL();
+	iMsgQueue = CDsaMsgQueue::NewL(this);
+	iStatus=EDirectStatusNone;
+	}
+
+void CWsDirectScreenAccess::Request(TInt handle)
+	{
+	if (iStatus!=EDirectStatusNone)
+		{
+		if (iStatus==EDirectStatusCompleted)
+			{
+			iMsgQueue->Cancel();
+			}
+		else
+			{
+			iWsOwner->PPanic(EWservPanicDirectMisuse);
+			}
+		}
+	iWsOwner->HandleToClientWindow(handle,&iWin);
+	iScreen=iWin->Screen();
+	STACK_REGION region;
+	iWin->GenerateTopRegion(region);
+	const TInt regionCount=region.Count();
+	region.Close();
+	SetReply(regionCount);
+	iStatus=EDirectStatusInitialising;
+	}
+
+void CWsDirectScreenAccess::GetRegion(TInt aNumRects)
+	{
+#if defined(_DEBUG)
+	if (iStatus!=EDirectStatusInitialising)
+		iWsOwner->PPanic(EWservPanicDirectMisuse);
+#endif
+	STACK_REGION region;
+	iWin->GenerateTopRegion(region);
+	const TInt regionCount=region.Count();
+	if (region.Count()==aNumRects)
+		{
+		iVisible.Copy(region);
+		if (iVisible.CheckError())
+			{
+			iStatus=EDirectStatusNone;
+			SetReply(KErrNotReady);
+			}
+		else
+			{
+			TPtrC8 rectList(REINTERPRET_CAST(const TUint8*,region.RectangleList()),region.Count()*sizeof(TRect));
+			CWsClient::ReplyBuf(rectList);
+			iStatus=EDirectStatusRunning;
+			Initiate();
+			iMsgQueue->Started();
+			SetReply(KMaxTInt);
+			}
+		}
+	else
+		{
+		SetReply(region.Count());
+		}
+	region.Close();
+	}
+
+void CWsDirectScreenAccess::Cancel()
+	{
+	TInt ret = 0;
+	switch (iStatus)
+		{
+#if defined(_DEBUG)
+	case EDirectStatusInitialising:
+		iWsOwner->PPanic(EWservPanicDirectMisuse);
+#endif
+	case EDirectStatusNone:
+		break;
+	case EDirectStatusRunning:
+		Terminate1();
+		Terminate2(); 
+		/*Fall through*/
+	case EDirectStatusCanceling:
+		ret = 1;
+		iMsgQueue->Send(RDirectScreenAccess::ETerminateCancel);	
+		break;
+	case EDirectStatusAbortedWindow:
+	case EDirectStatusAbortedGlobal:
+		CorrectScreen();
+		break;
+	case EDirectStatusCompleted:
+		break;
+	default:
+			{
+			}
+		}
+	SetReply(ret);
+	iStatus=EDirectStatusNone;
+	}
+
+void CWsDirectScreenAccess::Aborted()
+	{
+	switch (iStatus)
+		{
+	case EDirectStatusRunning:
+		Terminate1();
+		Terminate2();
+		iStatus=EDirectStatusCanceling;
+		break;
+	case EDirectStatusAbortedWindow:
+	case EDirectStatusAbortedGlobal:
+		CorrectScreen(); 
+		/*Fall through*/
+	case EDirectStatusCompleted:
+		iStatus=EDirectStatusNone;
+		break;
+	default:
+		iWsOwner->PPanic(EWservPanicDirectMisuse);
+		}
+	}
+
+void CWsDirectScreenAccess::AbortNow()
+	{
+	if (iStatus!=EDirectStatusRunning)
+		{
+		iWsOwner->PPanic(EWservPanicDirectMisuse);
+		}
+	SignalAbort(RDirectScreenAccess::ETerminateRegion);
+	TRequestStatus timerStatus;
+	RTimer& timer=CWsTop::Timer();
+	timer.After(timerStatus,400000);		//0.4secs
+	User::WaitForRequest(iMsgQueue->Status(),timerStatus);
+	if (timerStatus!=KRequestPending)
+		{
+		Abort();
+		}
+	else
+		{
+		CancelAbortObject();
+		timer.Cancel();
+		User::WaitForRequest(timerStatus);
+		}
+	}
+
+void CWsDirectScreenAccess::SignalAbort(RDirectScreenAccess::TTerminationReasons aReason)
+	{
+	DeleteRegionSyncWatchcat();
+	
+	iAbortReason=aReason;
+	if (iStatus==EDirectStatusAbortedWindow)
+		{
+		WS_ASSERT_DEBUG(iAbortReason>RDirectScreenAccess::ETerminateRegion, EWsPanicDirectScreenAccess);
+		Terminate2();
+		return;
+		}
+	if (iStatus!=EDirectStatusRunning)
+		{
+		iWsOwner->PPanic(EWservPanicDirectMisuse);
+		}
+	if (RDirectScreenAccess::ETerminateCancel != aReason)
+		{
+		TInt err;
+		TRAP(err, iRegionSync = CWsDirectScreenAccess::CDSARegionSyncTimer::NewL( *this ) );
+		if ( KErrNone == err )
+			{
+			iFrozenRegion.Copy( iVisible );			
+			Screen()->DSARegionSyncStart( *this );
+			}
+		}
+	iMsgQueue->Send(aReason);
+	}
+
+void CWsDirectScreenAccess::CancelAbortObject()
+	{
+	iMsgQueue->Complete();
+	iMsgQueue->Cancel();
+	iStatus=EDirectStatusNone;
+	Terminate1();
+	Terminate2();
+	}
+
+void CWsDirectScreenAccess::Abort()
+	{
+	if ( iStatus == EDirectStatusRunning ) 	
+		{
+		Terminate1();
+		if (iMsgQueue->Status()==KRequestPending)
+			iStatus=(iAbortReason<=RDirectScreenAccess::ETerminateRegion ? EDirectStatusAbortedWindow:EDirectStatusAbortedGlobal);
+		else
+			iStatus=EDirectStatusCompleted;
+		if (iStatus!=EDirectStatusAbortedWindow)
+			Terminate2();
+		}
+	}
+
+
+TInt CWsDirectScreenAccess::GetSendQueue()
+	{
+	TInt ret = iMsgQueue->CreateSendQueue();
+	if(ret == KErrNone)
+		{
+		iWsOwner->SetResponseHandle(iMsgQueue->SendQueue());	
+		}
+	return ret;
+	}
+
+TInt CWsDirectScreenAccess::GetRecQueue()
+	{
+	TInt ret = iMsgQueue->CreateRecQueue();
+	if(ret == KErrNone)
+		{
+		iWsOwner->SetResponseHandle(iMsgQueue->RecQueue());	
+		}
+	return ret;
+	}
+
+
+void CWsDirectScreenAccess::CommandL(TInt aOpcode,const TAny* aCmdData)
+	{
+	TWsDirectCmdUnion pData;
+	pData.any=aCmdData;
+	switch(aOpcode)
+		{
+		case EWsDirectOpFree:
+			delete this;
+			break;
+		case EWsDirectOpRequest:
+			Request(*pData.Int);
+			break;
+		case EWsDirectOpInitFailed:
+	#if defined(_DEBUG)
+			if (iStatus!=EDirectStatusInitialising)
+				{
+				iWsOwner->PPanic(EWservPanicDirectMisuse);
+				}
+	#endif
+			iStatus=EDirectStatusNone;
+			break;
+		case EWsDirectOpGetRegion:
+			GetRegion(*pData.Int);
+			break;
+		case EWsDirectOpCancel:
+			Cancel();
+			break;
+		case EWsDirectOpGetSendQueue:
+			GetSendQueue();
+			break;
+		case EWsDirectOpGetRecQueue:
+			GetRecQueue();
+			break;
+		default:
+			OwnerPanic(EWservPanicOpcode);
+			break;
+		}
+	}
+
+void CWsDirectScreenAccess::Initiate()
+	{
+	iWin->AddDSA(*this);
+	iScreen->AddDirect(*this);
+	if ( IsSyncTimeoutPending() )
+		{
+		Screen()->DSARegionSyncOver( *this );
+		
+		RRegion deltaRgn;
+		deltaRgn.Copy( iFrozenRegion );
+		
+		deltaRgn.SubRegion( iVisible );
+		deltaRgn.Tidy();
+		
+		if ( !deltaRgn.IsEmpty() )
+			{
+			Screen()->ScheduleRegionUpdate( &deltaRgn );
+			}
+		
+		deltaRgn.Close();
+		iFrozenRegion.Clear();
+
+		DeleteRegionSyncWatchcat();
+		}
+	}
+TBool CWsDirectScreenAccess::IsAbortRequired(const TRegion& aTopVisibleRegion) const
+	{
+	return ( iStatus == EDirectStatusRunning ) && !RegionsMatch(aTopVisibleRegion, iVisible);
+	}
+
+void CWsDirectScreenAccess::Terminate1()
+	{
+	WS_ASSERT_DEBUG(!iWin->DSAs().IsEmpty(), EWsPanicDirectScreenAccess);
+	iWin->RemoveDSA(*this);
+	}
+
+void CWsDirectScreenAccess::Terminate2()
+	{
+	iScreen->RemoveDirect(*this);
+	WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
+	}
+
+void CWsDirectScreenAccess::CorrectScreen()
+	{
+	if (iAbortReason<=RDirectScreenAccess::ETerminateRegion)
+		{
+		Terminate2();
+		RootWindow()->Invalidate(&iVisible);
+		}
+	else
+		RootWindow()->InvalidateWholeScreen();
+
+	WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
+	}
+
+
+
+#if defined(_DEBUG)
+TBool CWsDirectScreenAccess::OnQueue()
+	{
+	return iScreen->IsDirectOnQueue(this);
+	}
+#endif
+
+
+TBool CWsDirectScreenAccess::IsSyncTimeoutPending() const
+	{
+	TBool res;
+	res = ( NULL != iRegionSync ) && ( iRegionSync->IsActive() );
+	return res; 
+	}
+
+void CWsDirectScreenAccess::CancelFrozenRegion()
+	{
+	if ( !iFrozenRegion.IsEmpty() )
+		{
+		Screen()->DSARegionSyncOver( *this );
+		Screen()->ScheduleRegionUpdate( &iFrozenRegion );
+		iFrozenRegion.Clear();
+		}	
+	}
+
+void CWsDirectScreenAccess::DeleteRegionSyncWatchcat()
+	{
+	if ( NULL != iRegionSync )
+		{
+		if ( iRegionSync->IsActive() )
+			{
+			iRegionSync->Cancel();			
+			}
+		delete iRegionSync;
+		iRegionSync = NULL;
+		}
+	CancelFrozenRegion();
+	}	
+
+void CWsDirectScreenAccess::RegionSyncTimeout()
+	{
+	CancelFrozenRegion();
+	}
+
+CWsDirectScreenAccess::CDSARegionSyncTimer* CWsDirectScreenAccess::CDSARegionSyncTimer::NewL(CWsDirectScreenAccess& aDSA)
+	{
+	CWsDirectScreenAccess::CDSARegionSyncTimer* self = new ( ELeave ) CWsDirectScreenAccess::CDSARegionSyncTimer( aDSA );
+	
+	CleanupStack::PushL( self );
+	self->ConstructL();
+	CleanupStack::Pop( self );
+	
+	CActiveScheduler::Add( self );
+	self->After( TTimeIntervalMicroSeconds32( KRegionSyncTimeoutMicrosec ) );
+	return self;
+	}
+	
+void CWsDirectScreenAccess::CDSARegionSyncTimer::RunL()
+	{
+	iDSA.RegionSyncTimeout();
+	}
+
+CWsDirectScreenAccess::CDSARegionSyncTimer::CDSARegionSyncTimer(CWsDirectScreenAccess& aDSA):
+	CTimer( CActive::EPriorityHigh ),
+	iDSA( aDSA )
+	{ } // empty	
+
+
+static TBool RegionsMatch(const TRegion & aOne, const TRegion & aTwo)
+	{
+	// Check if the regions have equal areas.
+	const TRect* rect1 = aOne.RectangleList();
+	TUint area1 = 0;
+	for(TInt i = 0; i < aOne.Count(); ++i)
+		{
+		area1 += (rect1->Width() * rect1->Height());
+		rect1++;
+		}
+
+	const TRect* rect2 = aTwo.RectangleList();
+	TUint area2 = 0;
+	for(TInt i = 0; i < aTwo.Count(); ++i)
+		{
+		area2 += (rect2->Width() * rect2->Height());
+		rect2++;
+		}
+	
+	if(area1 != area2)
+		{
+		return EFalse;
+		}
+
+	// Check if one region is completely contained within the other.
+	STACK_REGION tempRegion;
+	tempRegion.Copy(aOne);	
+	tempRegion.SubRegion(aTwo);
+
+	const TBool ret(tempRegion.IsEmpty());
+	tempRegion.Close();
+
+	return ret;
+	}
+