sl@0: // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Direct Screen Access class, to allow the client to draw directly to the screen sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include "Direct.H" sl@0: #include "server.h" sl@0: #include "rootwin.h" sl@0: #include "wstop.h" sl@0: #include "panics.h" sl@0: #include sl@0: sl@0: const TInt KMsgQueueLength = 1; sl@0: sl@0: static TBool RegionsMatch(const TRegion & aOne, const TRegion & aTwo); sl@0: sl@0: sl@0: CDsaMsgQueue* CDsaMsgQueue::NewL(CWsDirectScreenAccess* aDirect) sl@0: { sl@0: CDsaMsgQueue* self = new(ELeave)CDsaMsgQueue; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aDirect); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: CDsaMsgQueue::CDsaMsgQueue() sl@0: {} sl@0: sl@0: CDsaMsgQueue::~CDsaMsgQueue() sl@0: { sl@0: delete iAborted; sl@0: iSendQueue.Close(); sl@0: iRecQueue.Close(); sl@0: } sl@0: sl@0: void CDsaMsgQueue::ConstructL(CWsDirectScreenAccess* aDirect) sl@0: { sl@0: iAborted=new(ELeave) CWsAbortDirect(aDirect,this); sl@0: } sl@0: sl@0: void CDsaMsgQueue::Cancel() sl@0: { sl@0: //purge the queue of data sl@0: TInt ret = KErrNone; sl@0: do sl@0: { sl@0: TInt data = 0; sl@0: ret = iRecQueue.Receive(&data,sizeof(TInt)); sl@0: }while(ret == KErrNone); sl@0: iAborted->Cancel(); sl@0: } sl@0: sl@0: TInt CDsaMsgQueue::Send(TInt aData) sl@0: { sl@0: return iSendQueue.Send(&aData,sizeof(TInt)); sl@0: } sl@0: sl@0: TInt CDsaMsgQueue::CreateSendQueue() sl@0: { sl@0: if(iSendQueue.Handle() == 0) sl@0: { sl@0: return iSendQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess); sl@0: } sl@0: else sl@0: { sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: TInt CDsaMsgQueue::CreateRecQueue() sl@0: { sl@0: if(iRecQueue.Handle() == 0) sl@0: { sl@0: return iRecQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess); sl@0: } sl@0: else sl@0: { sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: RMsgQueueBase* CDsaMsgQueue::SendQueue() sl@0: { sl@0: return &iSendQueue; sl@0: } sl@0: sl@0: RMsgQueueBase* CDsaMsgQueue::RecQueue() sl@0: { sl@0: return &iRecQueue; sl@0: } sl@0: sl@0: void CDsaMsgQueue::Started() sl@0: { sl@0: iAborted->Started(); sl@0: } sl@0: sl@0: void CDsaMsgQueue::Complete() sl@0: { sl@0: iAborted->Complete(RDirectScreenAccess::ETerminateCancel); sl@0: } sl@0: sl@0: void CDsaMsgQueue::CompleteAbort() sl@0: { sl@0: iAborted->Complete(KErrNone); sl@0: } sl@0: sl@0: TInt CDsaMsgQueue::ReceiveData() sl@0: { sl@0: TInt data = 0; sl@0: iRecQueue.Receive(&data,sizeof(TInt)); sl@0: return data; sl@0: } sl@0: sl@0: /*CWsAbortDirect*/ sl@0: sl@0: CWsAbortDirect::CWsAbortDirect(CWsDirectScreenAccess* aDirect,CDsaMsgQueue* aParent) : CActive(EDirectAbort), iDirect(aDirect),iParent(aParent) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: CWsAbortDirect::~CWsAbortDirect() sl@0: { sl@0: Cancel(); sl@0: } sl@0: sl@0: void CWsAbortDirect::Started() sl@0: { sl@0: iStatus=KRequestPending; sl@0: TRequestStatus& status = iStatus; sl@0: iParent->RecQueue()->NotifyDataAvailable(status); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CWsAbortDirect::RunL() sl@0: { sl@0: iParent->ReceiveData(); sl@0: iParent->RecQueue()->CancelDataAvailable(); sl@0: iDirect->Aborted(); sl@0: } sl@0: sl@0: void CWsAbortDirect::DoCancel() sl@0: { sl@0: iParent->RecQueue()->CancelDataAvailable(); sl@0: if (iStatus==KRequestPending) sl@0: { sl@0: Complete(KErrNone); sl@0: } sl@0: } sl@0: sl@0: void CWsAbortDirect::Complete(TInt aReason) sl@0: { sl@0: if(IsActive()) sl@0: { sl@0: TRequestStatus* status=&iStatus; sl@0: RThread().RequestComplete(status,aReason); sl@0: } sl@0: } sl@0: sl@0: sl@0: /*CWsDirectScreenAccess*/ sl@0: sl@0: CWsDirectScreenAccess* CWsDirectScreenAccess::NewL(CWsClient* aOwner) sl@0: { sl@0: CWsDirectScreenAccess* self = new(ELeave) CWsDirectScreenAccess(aOwner); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: CWsDirectScreenAccess::~CWsDirectScreenAccess() sl@0: { sl@0: DeleteRegionSyncWatchcat(); sl@0: iFrozenRegion.Close(); sl@0: iVisible.Close(); sl@0: if (iStatus!=EDirectStatusTimeNotCreated) sl@0: { sl@0: if (iStatus==EDirectStatusRunning) sl@0: AbortNow(); sl@0: if (iStatus>=EDirectStatusAborted) sl@0: CorrectScreen(); sl@0: } sl@0: WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess); sl@0: delete iMsgQueue; sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::ConstructL() sl@0: { sl@0: NewObjL(); sl@0: iMsgQueue = CDsaMsgQueue::NewL(this); sl@0: iStatus=EDirectStatusNone; sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::Request(TInt handle) sl@0: { sl@0: if (iStatus!=EDirectStatusNone) sl@0: { sl@0: if (iStatus==EDirectStatusCompleted) sl@0: { sl@0: iMsgQueue->Cancel(); sl@0: } sl@0: else sl@0: { sl@0: iWsOwner->PPanic(EWservPanicDirectMisuse); sl@0: } sl@0: } sl@0: iWsOwner->HandleToClientWindow(handle,&iWin); sl@0: iScreen=iWin->Screen(); sl@0: STACK_REGION region; sl@0: iWin->GenerateTopRegion(region); sl@0: const TInt regionCount=region.Count(); sl@0: region.Close(); sl@0: SetReply(regionCount); sl@0: iStatus=EDirectStatusInitialising; sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::GetRegion(TInt aNumRects) sl@0: { sl@0: #if defined(_DEBUG) sl@0: if (iStatus!=EDirectStatusInitialising) sl@0: iWsOwner->PPanic(EWservPanicDirectMisuse); sl@0: #endif sl@0: STACK_REGION region; sl@0: iWin->GenerateTopRegion(region); sl@0: const TInt regionCount=region.Count(); sl@0: if (region.Count()==aNumRects) sl@0: { sl@0: iVisible.Copy(region); sl@0: if (iVisible.CheckError()) sl@0: { sl@0: iStatus=EDirectStatusNone; sl@0: SetReply(KErrNotReady); sl@0: } sl@0: else sl@0: { sl@0: TPtrC8 rectList(REINTERPRET_CAST(const TUint8*,region.RectangleList()),region.Count()*sizeof(TRect)); sl@0: CWsClient::ReplyBuf(rectList); sl@0: iStatus=EDirectStatusRunning; sl@0: Initiate(); sl@0: iMsgQueue->Started(); sl@0: SetReply(KMaxTInt); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: SetReply(region.Count()); sl@0: } sl@0: region.Close(); sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::Cancel() sl@0: { sl@0: TInt ret = 0; sl@0: switch (iStatus) sl@0: { sl@0: #if defined(_DEBUG) sl@0: case EDirectStatusInitialising: sl@0: iWsOwner->PPanic(EWservPanicDirectMisuse); sl@0: #endif sl@0: case EDirectStatusNone: sl@0: break; sl@0: case EDirectStatusRunning: sl@0: Terminate1(); sl@0: Terminate2(); sl@0: /*Fall through*/ sl@0: case EDirectStatusCanceling: sl@0: ret = 1; sl@0: iMsgQueue->Send(RDirectScreenAccess::ETerminateCancel); sl@0: break; sl@0: case EDirectStatusAbortedWindow: sl@0: case EDirectStatusAbortedGlobal: sl@0: CorrectScreen(); sl@0: break; sl@0: case EDirectStatusCompleted: sl@0: break; sl@0: default: sl@0: { sl@0: } sl@0: } sl@0: SetReply(ret); sl@0: iStatus=EDirectStatusNone; sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::Aborted() sl@0: { sl@0: switch (iStatus) sl@0: { sl@0: case EDirectStatusRunning: sl@0: Terminate1(); sl@0: Terminate2(); sl@0: iStatus=EDirectStatusCanceling; sl@0: break; sl@0: case EDirectStatusAbortedWindow: sl@0: case EDirectStatusAbortedGlobal: sl@0: CorrectScreen(); sl@0: /*Fall through*/ sl@0: case EDirectStatusCompleted: sl@0: iStatus=EDirectStatusNone; sl@0: break; sl@0: default: sl@0: iWsOwner->PPanic(EWservPanicDirectMisuse); sl@0: } sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::AbortNow() sl@0: { sl@0: if (iStatus!=EDirectStatusRunning) sl@0: { sl@0: iWsOwner->PPanic(EWservPanicDirectMisuse); sl@0: } sl@0: SignalAbort(RDirectScreenAccess::ETerminateRegion); sl@0: TRequestStatus timerStatus; sl@0: RTimer& timer=CWsTop::Timer(); sl@0: timer.After(timerStatus,400000); //0.4secs sl@0: User::WaitForRequest(iMsgQueue->Status(),timerStatus); sl@0: if (timerStatus!=KRequestPending) sl@0: { sl@0: Abort(); sl@0: } sl@0: else sl@0: { sl@0: CancelAbortObject(); sl@0: timer.Cancel(); sl@0: User::WaitForRequest(timerStatus); sl@0: } sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::SignalAbort(RDirectScreenAccess::TTerminationReasons aReason) sl@0: { sl@0: DeleteRegionSyncWatchcat(); sl@0: sl@0: iAbortReason=aReason; sl@0: if (iStatus==EDirectStatusAbortedWindow) sl@0: { sl@0: WS_ASSERT_DEBUG(iAbortReason>RDirectScreenAccess::ETerminateRegion, EWsPanicDirectScreenAccess); sl@0: Terminate2(); sl@0: return; sl@0: } sl@0: if (iStatus!=EDirectStatusRunning) sl@0: { sl@0: iWsOwner->PPanic(EWservPanicDirectMisuse); sl@0: } sl@0: if (RDirectScreenAccess::ETerminateCancel != aReason) sl@0: { sl@0: TInt err; sl@0: TRAP(err, iRegionSync = CWsDirectScreenAccess::CDSARegionSyncTimer::NewL( *this ) ); sl@0: if ( KErrNone == err ) sl@0: { sl@0: iFrozenRegion.Copy( iVisible ); sl@0: Screen()->DSARegionSyncStart( *this ); sl@0: } sl@0: } sl@0: iMsgQueue->Send(aReason); sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::CancelAbortObject() sl@0: { sl@0: iMsgQueue->Complete(); sl@0: iMsgQueue->Cancel(); sl@0: iStatus=EDirectStatusNone; sl@0: Terminate1(); sl@0: Terminate2(); sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::Abort() sl@0: { sl@0: if ( iStatus == EDirectStatusRunning ) sl@0: { sl@0: Terminate1(); sl@0: if (iMsgQueue->Status()==KRequestPending) sl@0: iStatus=(iAbortReason<=RDirectScreenAccess::ETerminateRegion ? EDirectStatusAbortedWindow:EDirectStatusAbortedGlobal); sl@0: else sl@0: iStatus=EDirectStatusCompleted; sl@0: if (iStatus!=EDirectStatusAbortedWindow) sl@0: Terminate2(); sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt CWsDirectScreenAccess::GetSendQueue() sl@0: { sl@0: TInt ret = iMsgQueue->CreateSendQueue(); sl@0: if(ret == KErrNone) sl@0: { sl@0: iWsOwner->SetResponseHandle(iMsgQueue->SendQueue()); sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: TInt CWsDirectScreenAccess::GetRecQueue() sl@0: { sl@0: TInt ret = iMsgQueue->CreateRecQueue(); sl@0: if(ret == KErrNone) sl@0: { sl@0: iWsOwner->SetResponseHandle(iMsgQueue->RecQueue()); sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: void CWsDirectScreenAccess::CommandL(TInt aOpcode,const TAny* aCmdData) sl@0: { sl@0: TWsDirectCmdUnion pData; sl@0: pData.any=aCmdData; sl@0: switch(aOpcode) sl@0: { sl@0: case EWsDirectOpFree: sl@0: delete this; sl@0: break; sl@0: case EWsDirectOpRequest: sl@0: Request(*pData.Int); sl@0: break; sl@0: case EWsDirectOpInitFailed: sl@0: #if defined(_DEBUG) sl@0: if (iStatus!=EDirectStatusInitialising) sl@0: { sl@0: iWsOwner->PPanic(EWservPanicDirectMisuse); sl@0: } sl@0: #endif sl@0: iStatus=EDirectStatusNone; sl@0: break; sl@0: case EWsDirectOpGetRegion: sl@0: GetRegion(*pData.Int); sl@0: break; sl@0: case EWsDirectOpCancel: sl@0: Cancel(); sl@0: break; sl@0: case EWsDirectOpGetSendQueue: sl@0: GetSendQueue(); sl@0: break; sl@0: case EWsDirectOpGetRecQueue: sl@0: GetRecQueue(); sl@0: break; sl@0: default: sl@0: OwnerPanic(EWservPanicOpcode); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::Initiate() sl@0: { sl@0: iWin->AddDSA(*this); sl@0: iScreen->AddDirect(*this); sl@0: if ( IsSyncTimeoutPending() ) sl@0: { sl@0: Screen()->DSARegionSyncOver( *this ); sl@0: sl@0: RRegion deltaRgn; sl@0: deltaRgn.Copy( iFrozenRegion ); sl@0: sl@0: deltaRgn.SubRegion( iVisible ); sl@0: deltaRgn.Tidy(); sl@0: sl@0: if ( !deltaRgn.IsEmpty() ) sl@0: { sl@0: Screen()->ScheduleRegionUpdate( &deltaRgn ); sl@0: } sl@0: sl@0: deltaRgn.Close(); sl@0: iFrozenRegion.Clear(); sl@0: sl@0: DeleteRegionSyncWatchcat(); sl@0: } sl@0: } sl@0: TBool CWsDirectScreenAccess::IsAbortRequired(const TRegion& aTopVisibleRegion) const sl@0: { sl@0: return ( iStatus == EDirectStatusRunning ) && !RegionsMatch(aTopVisibleRegion, iVisible); sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::Terminate1() sl@0: { sl@0: WS_ASSERT_DEBUG(!iWin->DSAs().IsEmpty(), EWsPanicDirectScreenAccess); sl@0: iWin->RemoveDSA(*this); sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::Terminate2() sl@0: { sl@0: iScreen->RemoveDirect(*this); sl@0: WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess); sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::CorrectScreen() sl@0: { sl@0: if (iAbortReason<=RDirectScreenAccess::ETerminateRegion) sl@0: { sl@0: Terminate2(); sl@0: RootWindow()->Invalidate(&iVisible); sl@0: } sl@0: else sl@0: RootWindow()->InvalidateWholeScreen(); sl@0: sl@0: WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess); sl@0: } sl@0: sl@0: sl@0: sl@0: #if defined(_DEBUG) sl@0: TBool CWsDirectScreenAccess::OnQueue() sl@0: { sl@0: return iScreen->IsDirectOnQueue(this); sl@0: } sl@0: #endif sl@0: sl@0: sl@0: TBool CWsDirectScreenAccess::IsSyncTimeoutPending() const sl@0: { sl@0: TBool res; sl@0: res = ( NULL != iRegionSync ) && ( iRegionSync->IsActive() ); sl@0: return res; sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::CancelFrozenRegion() sl@0: { sl@0: if ( !iFrozenRegion.IsEmpty() ) sl@0: { sl@0: Screen()->DSARegionSyncOver( *this ); sl@0: Screen()->ScheduleRegionUpdate( &iFrozenRegion ); sl@0: iFrozenRegion.Clear(); sl@0: } sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::DeleteRegionSyncWatchcat() sl@0: { sl@0: if ( NULL != iRegionSync ) sl@0: { sl@0: if ( iRegionSync->IsActive() ) sl@0: { sl@0: iRegionSync->Cancel(); sl@0: } sl@0: delete iRegionSync; sl@0: iRegionSync = NULL; sl@0: } sl@0: CancelFrozenRegion(); sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::RegionSyncTimeout() sl@0: { sl@0: CancelFrozenRegion(); sl@0: } sl@0: sl@0: CWsDirectScreenAccess::CDSARegionSyncTimer* CWsDirectScreenAccess::CDSARegionSyncTimer::NewL(CWsDirectScreenAccess& aDSA) sl@0: { sl@0: CWsDirectScreenAccess::CDSARegionSyncTimer* self = new ( ELeave ) CWsDirectScreenAccess::CDSARegionSyncTimer( aDSA ); sl@0: sl@0: CleanupStack::PushL( self ); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop( self ); sl@0: sl@0: CActiveScheduler::Add( self ); sl@0: self->After( TTimeIntervalMicroSeconds32( KRegionSyncTimeoutMicrosec ) ); sl@0: return self; sl@0: } sl@0: sl@0: void CWsDirectScreenAccess::CDSARegionSyncTimer::RunL() sl@0: { sl@0: iDSA.RegionSyncTimeout(); sl@0: } sl@0: sl@0: CWsDirectScreenAccess::CDSARegionSyncTimer::CDSARegionSyncTimer(CWsDirectScreenAccess& aDSA): sl@0: CTimer( CActive::EPriorityHigh ), sl@0: iDSA( aDSA ) sl@0: { } // empty sl@0: sl@0: sl@0: static TBool RegionsMatch(const TRegion & aOne, const TRegion & aTwo) sl@0: { sl@0: // Check if the regions have equal areas. sl@0: const TRect* rect1 = aOne.RectangleList(); sl@0: TUint area1 = 0; sl@0: for(TInt i = 0; i < aOne.Count(); ++i) sl@0: { sl@0: area1 += (rect1->Width() * rect1->Height()); sl@0: rect1++; sl@0: } sl@0: sl@0: const TRect* rect2 = aTwo.RectangleList(); sl@0: TUint area2 = 0; sl@0: for(TInt i = 0; i < aTwo.Count(); ++i) sl@0: { sl@0: area2 += (rect2->Width() * rect2->Height()); sl@0: rect2++; sl@0: } sl@0: sl@0: if(area1 != area2) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: // Check if one region is completely contained within the other. sl@0: STACK_REGION tempRegion; sl@0: tempRegion.Copy(aOne); sl@0: tempRegion.SubRegion(aTwo); sl@0: sl@0: const TBool ret(tempRegion.IsEmpty()); sl@0: tempRegion.Close(); sl@0: sl@0: return ret; sl@0: } sl@0: