diff -r 000000000000 -r 5d03bc08d59c windowing/windowserver/nonnga/SERVER/Direct.CPP --- /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 +#include "Direct.H" +#include "server.h" +#include "rootwin.h" +#include "wstop.h" +#include "panics.h" +#include + +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; + } +