First public contribution.
1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // Direct Screen Access class, to allow the client to draw directly to the screen
24 #include <e32msgqueue.h>
26 const TInt KMsgQueueLength = 1;
28 static TBool RegionsMatch(const TRegion & aOne, const TRegion & aTwo);
31 CDsaMsgQueue* CDsaMsgQueue::NewL(CWsDirectScreenAccess* aDirect)
33 CDsaMsgQueue* self = new(ELeave)CDsaMsgQueue;
34 CleanupStack::PushL(self);
35 self->ConstructL(aDirect);
36 CleanupStack::Pop(self);
40 CDsaMsgQueue::CDsaMsgQueue()
43 CDsaMsgQueue::~CDsaMsgQueue()
50 void CDsaMsgQueue::ConstructL(CWsDirectScreenAccess* aDirect)
52 iAborted=new(ELeave) CWsAbortDirect(aDirect,this);
55 void CDsaMsgQueue::Cancel()
57 //purge the queue of data
62 ret = iRecQueue.Receive(&data,sizeof(TInt));
63 }while(ret == KErrNone);
67 TInt CDsaMsgQueue::Send(TInt aData)
69 return iSendQueue.Send(&aData,sizeof(TInt));
72 TInt CDsaMsgQueue::CreateSendQueue()
74 if(iSendQueue.Handle() == 0)
76 return iSendQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess);
84 TInt CDsaMsgQueue::CreateRecQueue()
86 if(iRecQueue.Handle() == 0)
88 return iRecQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess);
96 RMsgQueueBase* CDsaMsgQueue::SendQueue()
101 RMsgQueueBase* CDsaMsgQueue::RecQueue()
106 void CDsaMsgQueue::Started()
111 void CDsaMsgQueue::Complete()
113 iAborted->Complete(RDirectScreenAccess::ETerminateCancel);
116 void CDsaMsgQueue::CompleteAbort()
118 iAborted->Complete(KErrNone);
121 TInt CDsaMsgQueue::ReceiveData()
124 iRecQueue.Receive(&data,sizeof(TInt));
130 CWsAbortDirect::CWsAbortDirect(CWsDirectScreenAccess* aDirect,CDsaMsgQueue* aParent) : CActive(EDirectAbort), iDirect(aDirect),iParent(aParent)
132 CActiveScheduler::Add(this);
135 CWsAbortDirect::~CWsAbortDirect()
140 void CWsAbortDirect::Started()
142 iStatus=KRequestPending;
143 TRequestStatus& status = iStatus;
144 iParent->RecQueue()->NotifyDataAvailable(status);
148 void CWsAbortDirect::RunL()
150 iParent->ReceiveData();
151 iParent->RecQueue()->CancelDataAvailable();
155 void CWsAbortDirect::DoCancel()
157 iParent->RecQueue()->CancelDataAvailable();
158 if (iStatus==KRequestPending)
164 void CWsAbortDirect::Complete(TInt aReason)
168 TRequestStatus* status=&iStatus;
169 RThread().RequestComplete(status,aReason);
174 /*CWsDirectScreenAccess*/
176 CWsDirectScreenAccess* CWsDirectScreenAccess::NewL(CWsClient* aOwner)
178 CWsDirectScreenAccess* self = new(ELeave) CWsDirectScreenAccess(aOwner);
179 CleanupStack::PushL(self);
181 CleanupStack::Pop(self);
185 CWsDirectScreenAccess::~CWsDirectScreenAccess()
187 DeleteRegionSyncWatchcat();
188 iFrozenRegion.Close();
190 if (iStatus!=EDirectStatusTimeNotCreated)
192 if (iStatus==EDirectStatusRunning)
194 if (iStatus>=EDirectStatusAborted)
197 WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
201 void CWsDirectScreenAccess::ConstructL()
204 iMsgQueue = CDsaMsgQueue::NewL(this);
205 iStatus=EDirectStatusNone;
208 void CWsDirectScreenAccess::Request(TInt handle)
210 if (iStatus!=EDirectStatusNone)
212 if (iStatus==EDirectStatusCompleted)
218 iWsOwner->PPanic(EWservPanicDirectMisuse);
221 iWsOwner->HandleToClientWindow(handle,&iWin);
222 iScreen=iWin->Screen();
224 iWin->GenerateTopRegion(region);
225 const TInt regionCount=region.Count();
227 SetReply(regionCount);
228 iStatus=EDirectStatusInitialising;
231 void CWsDirectScreenAccess::GetRegion(TInt aNumRects)
234 if (iStatus!=EDirectStatusInitialising)
235 iWsOwner->PPanic(EWservPanicDirectMisuse);
238 iWin->GenerateTopRegion(region);
239 const TInt regionCount=region.Count();
240 if (region.Count()==aNumRects)
242 iVisible.Copy(region);
243 if (iVisible.CheckError())
245 iStatus=EDirectStatusNone;
246 SetReply(KErrNotReady);
250 TPtrC8 rectList(REINTERPRET_CAST(const TUint8*,region.RectangleList()),region.Count()*sizeof(TRect));
251 CWsClient::ReplyBuf(rectList);
252 iStatus=EDirectStatusRunning;
254 iMsgQueue->Started();
260 SetReply(region.Count());
265 void CWsDirectScreenAccess::Cancel()
271 case EDirectStatusInitialising:
272 iWsOwner->PPanic(EWservPanicDirectMisuse);
274 case EDirectStatusNone:
276 case EDirectStatusRunning:
280 case EDirectStatusCanceling:
282 iMsgQueue->Send(RDirectScreenAccess::ETerminateCancel);
284 case EDirectStatusAbortedWindow:
285 case EDirectStatusAbortedGlobal:
288 case EDirectStatusCompleted:
295 iStatus=EDirectStatusNone;
298 void CWsDirectScreenAccess::Aborted()
302 case EDirectStatusRunning:
305 iStatus=EDirectStatusCanceling;
307 case EDirectStatusAbortedWindow:
308 case EDirectStatusAbortedGlobal:
311 case EDirectStatusCompleted:
312 iStatus=EDirectStatusNone;
315 iWsOwner->PPanic(EWservPanicDirectMisuse);
319 void CWsDirectScreenAccess::AbortNow()
321 if (iStatus!=EDirectStatusRunning)
323 iWsOwner->PPanic(EWservPanicDirectMisuse);
325 SignalAbort(RDirectScreenAccess::ETerminateRegion);
326 TRequestStatus timerStatus;
327 RTimer& timer=CWsTop::Timer();
328 timer.After(timerStatus,400000); //0.4secs
329 User::WaitForRequest(iMsgQueue->Status(),timerStatus);
330 if (timerStatus!=KRequestPending)
338 User::WaitForRequest(timerStatus);
342 void CWsDirectScreenAccess::SignalAbort(RDirectScreenAccess::TTerminationReasons aReason)
344 DeleteRegionSyncWatchcat();
346 iAbortReason=aReason;
347 if (iStatus==EDirectStatusAbortedWindow)
349 WS_ASSERT_DEBUG(iAbortReason>RDirectScreenAccess::ETerminateRegion, EWsPanicDirectScreenAccess);
353 if (iStatus!=EDirectStatusRunning)
355 iWsOwner->PPanic(EWservPanicDirectMisuse);
357 if (RDirectScreenAccess::ETerminateCancel != aReason)
360 TRAP(err, iRegionSync = CWsDirectScreenAccess::CDSARegionSyncTimer::NewL( *this ) );
361 if ( KErrNone == err )
363 iFrozenRegion.Copy( iVisible );
364 Screen()->DSARegionSyncStart( *this );
367 iMsgQueue->Send(aReason);
370 void CWsDirectScreenAccess::CancelAbortObject()
372 iMsgQueue->Complete();
374 iStatus=EDirectStatusNone;
379 void CWsDirectScreenAccess::Abort()
381 if ( iStatus == EDirectStatusRunning )
384 if (iMsgQueue->Status()==KRequestPending)
385 iStatus=(iAbortReason<=RDirectScreenAccess::ETerminateRegion ? EDirectStatusAbortedWindow:EDirectStatusAbortedGlobal);
387 iStatus=EDirectStatusCompleted;
388 if (iStatus!=EDirectStatusAbortedWindow)
394 TInt CWsDirectScreenAccess::GetSendQueue()
396 TInt ret = iMsgQueue->CreateSendQueue();
399 iWsOwner->SetResponseHandle(iMsgQueue->SendQueue());
404 TInt CWsDirectScreenAccess::GetRecQueue()
406 TInt ret = iMsgQueue->CreateRecQueue();
409 iWsOwner->SetResponseHandle(iMsgQueue->RecQueue());
415 void CWsDirectScreenAccess::CommandL(TInt aOpcode,const TAny* aCmdData)
417 TWsDirectCmdUnion pData;
421 case EWsDirectOpFree:
424 case EWsDirectOpRequest:
427 case EWsDirectOpInitFailed:
429 if (iStatus!=EDirectStatusInitialising)
431 iWsOwner->PPanic(EWservPanicDirectMisuse);
434 iStatus=EDirectStatusNone;
436 case EWsDirectOpGetRegion:
437 GetRegion(*pData.Int);
439 case EWsDirectOpCancel:
442 case EWsDirectOpGetSendQueue:
445 case EWsDirectOpGetRecQueue:
449 OwnerPanic(EWservPanicOpcode);
454 void CWsDirectScreenAccess::Initiate()
457 iScreen->AddDirect(*this);
458 if ( IsSyncTimeoutPending() )
460 Screen()->DSARegionSyncOver( *this );
463 deltaRgn.Copy( iFrozenRegion );
465 deltaRgn.SubRegion( iVisible );
468 if ( !deltaRgn.IsEmpty() )
470 Screen()->ScheduleRegionUpdate( &deltaRgn );
474 iFrozenRegion.Clear();
476 DeleteRegionSyncWatchcat();
479 TBool CWsDirectScreenAccess::IsAbortRequired(const TRegion& aTopVisibleRegion) const
481 return ( iStatus == EDirectStatusRunning ) && !RegionsMatch(aTopVisibleRegion, iVisible);
484 void CWsDirectScreenAccess::Terminate1()
486 WS_ASSERT_DEBUG(!iWin->DSAs().IsEmpty(), EWsPanicDirectScreenAccess);
487 iWin->RemoveDSA(*this);
490 void CWsDirectScreenAccess::Terminate2()
492 iScreen->RemoveDirect(*this);
493 WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
496 void CWsDirectScreenAccess::CorrectScreen()
498 if (iAbortReason<=RDirectScreenAccess::ETerminateRegion)
501 RootWindow()->Invalidate(&iVisible);
504 RootWindow()->InvalidateWholeScreen();
506 WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
512 TBool CWsDirectScreenAccess::OnQueue()
514 return iScreen->IsDirectOnQueue(this);
519 TBool CWsDirectScreenAccess::IsSyncTimeoutPending() const
522 res = ( NULL != iRegionSync ) && ( iRegionSync->IsActive() );
526 void CWsDirectScreenAccess::CancelFrozenRegion()
528 if ( !iFrozenRegion.IsEmpty() )
530 Screen()->DSARegionSyncOver( *this );
531 Screen()->ScheduleRegionUpdate( &iFrozenRegion );
532 iFrozenRegion.Clear();
536 void CWsDirectScreenAccess::DeleteRegionSyncWatchcat()
538 if ( NULL != iRegionSync )
540 if ( iRegionSync->IsActive() )
542 iRegionSync->Cancel();
547 CancelFrozenRegion();
550 void CWsDirectScreenAccess::RegionSyncTimeout()
552 CancelFrozenRegion();
555 CWsDirectScreenAccess::CDSARegionSyncTimer* CWsDirectScreenAccess::CDSARegionSyncTimer::NewL(CWsDirectScreenAccess& aDSA)
557 CWsDirectScreenAccess::CDSARegionSyncTimer* self = new ( ELeave ) CWsDirectScreenAccess::CDSARegionSyncTimer( aDSA );
559 CleanupStack::PushL( self );
561 CleanupStack::Pop( self );
563 CActiveScheduler::Add( self );
564 self->After( TTimeIntervalMicroSeconds32( KRegionSyncTimeoutMicrosec ) );
568 void CWsDirectScreenAccess::CDSARegionSyncTimer::RunL()
570 iDSA.RegionSyncTimeout();
573 CWsDirectScreenAccess::CDSARegionSyncTimer::CDSARegionSyncTimer(CWsDirectScreenAccess& aDSA):
574 CTimer( CActive::EPriorityHigh ),
579 static TBool RegionsMatch(const TRegion & aOne, const TRegion & aTwo)
581 // Check if the regions have equal areas.
582 const TRect* rect1 = aOne.RectangleList();
584 for(TInt i = 0; i < aOne.Count(); ++i)
586 area1 += (rect1->Width() * rect1->Height());
590 const TRect* rect2 = aTwo.RectangleList();
592 for(TInt i = 0; i < aTwo.Count(); ++i)
594 area2 += (rect2->Width() * rect2->Height());
603 // Check if one region is completely contained within the other.
604 STACK_REGION tempRegion;
605 tempRegion.Copy(aOne);
606 tempRegion.SubRegion(aTwo);
608 const TBool ret(tempRegion.IsEmpty());