diff -r 000000000000 -r 5d03bc08d59c windowing/windowserver/nga/SERVER/openwfc/Direct.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowing/windowserver/nga/SERVER/openwfc/Direct.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,571 @@ +// 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 +#include "Direct.H" +#include "server.h" +#include "rootwin.h" +#include "wstop.h" +#include "panics.h" +#include + +const TInt KMsgQueueLength = 1; + +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; + iParent->RecQueue()->CancelDataAvailable(); + RThread().RequestComplete(status,aReason); + } + } + + +/*CWsDirectScreenAccess*/ + +CWsDirectScreenAccess* CWsDirectScreenAccess::NewL(CWsClient* aOwner,TBool aRegionTrackingOnly) + { + CWsDirectScreenAccess* self = new(ELeave) CWsDirectScreenAccess(aOwner); + CleanupStack::PushL(self); + self->ConstructL(aRegionTrackingOnly); + CleanupStack::Pop(self); + return self; + } + +CWsDirectScreenAccess::~CWsDirectScreenAccess() + { + iVisible.Close(); + if (iStatus!=EDirectStatusTimeNotCreated) + { + if (iStatus==EDirectStatusRunning) + AbortNow(); + if (iStatus>=EDirectStatusAborted) + CorrectScreen(); + } + WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess); + if(!iRegionTrackingOnly) + { + CScreen* screen = Screen(); + __ASSERT_DEBUG(screen,Panic(EWsPanicNoScreen)); + screen->ReleaseDsaScreenDevice(); + } + delete iMsgQueue; + } + +void CWsDirectScreenAccess::ConstructL(TBool aRegionTrackingOnly) + { + NewObjL(); + iMsgQueue = CDsaMsgQueue::NewL(this); + iStatus=EDirectStatusNone; + iRegionTrackingOnly = aRegionTrackingOnly; + if(!iRegionTrackingOnly) + { + //The Direct Screen Access object is going to be used to draw to the screen so we need to: + //1)allocate the buffer + //2)initialize the DSA device and surface + CScreen* screen = Screen(); + __ASSERT_DEBUG(screen,Panic(EWsPanicNoScreen)); + screen->AcquireDsaScreenDeviceL(); + } + } + +void CWsDirectScreenAccess::Request(TInt handle) + { + if (iStatus!=EDirectStatusNone) + { + if (iStatus==EDirectStatusCompleted) + { + iMsgQueue->Cancel(); + } + else + { + iWsOwner->PPanic(EWservPanicDirectMisuse); + } + } + iWsOwner->HandleToClientWindow(handle,&iWin); + STACK_REGION region; + iWin->GenerateTopRegion(region); + + //clip the draw region with DSA buffer + TRect dsaBuffer(TPoint(0,0), iScreen->DSASizeInPixels()); + MWsDisplayMapping *dispMap = iScreen->DisplayMapping(); + TRect dsaBufferInAppSpace; + if(dispMap) + { + dispMap->MapCoordinates(EDirectScreenAccessSpace,dsaBuffer,EApplicationSpace,dsaBufferInAppSpace); + } + else + { + dsaBufferInAppSpace = dsaBuffer; + } + region.ClipRect(dsaBufferInAppSpace); + 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 winVisibleRegion, region; + iWin->GenerateTopRegion(winVisibleRegion); + //clip the draw region with DSA buffer + TRect dsaBuffer(TPoint(0,0), iScreen->DSASizeInPixels()); + MWsDisplayMapping *dispMap = iScreen->DisplayMapping(); + TRect dsaBufferInAppSpace; + if(dispMap) + { + dispMap->MapCoordinates(EDirectScreenAccessSpace,dsaBuffer,EApplicationSpace,dsaBufferInAppSpace); + } + else + { + dsaBufferInAppSpace = dsaBuffer; + } + region.Copy(winVisibleRegion); + region.ClipRect(dsaBufferInAppSpace); + + const TInt regionCount=region.Count(); + if (region.Count()==aNumRects) + { + iVisible.Copy(winVisibleRegion); + if (iVisible.CheckError()) + { + iStatus=EDirectStatusNone; + SetReply(KErrNotReady); + } + else + { + TInt error = Initiate(); + + if (!error) + { + TPtrC8 rectList(REINTERPRET_CAST(const TUint8*,region.RectangleList()),region.Count()*sizeof(TRect)); + CWsClient::ReplyBuf(rectList); + iStatus=EDirectStatusRunning; + iMsgQueue->Started(); + SetReply(KMaxTInt); + } + else + { + iStatus=EDirectStatusNone; + SetReply(error); + } + } + } + else + { + SetReply(region.Count()); + } + region.Close(); + winVisibleRegion.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) + { + iAbortReason=aReason; + if (iStatus==EDirectStatusAbortedWindow) + { + WS_ASSERT_DEBUG(iAbortReason>RDirectScreenAccess::ETerminateRegion, EWsPanicDirectScreenAccess); + Terminate2(); + return; + } + if (iStatus!=EDirectStatusRunning) + { + iWsOwner->PPanic(EWservPanicDirectMisuse); + } + 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; + } + } + +TInt CWsDirectScreenAccess::Initiate() + { + const TInt err = iWin->AddDSA(*this); + if(err) + return err; + + iScreen->AddDirect(*this); + return KErrNone; + } + +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; + } + +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); + iScreen->UpdateDsa(); + } + +#if defined(_DEBUG) +TBool CWsDirectScreenAccess::OnQueue() + { + return iScreen->IsDirectOnQueue(this); + } +#endif