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 CDsaMsgQueue* CDsaMsgQueue::NewL(CWsDirectScreenAccess* aDirect)
30 CDsaMsgQueue* self = new(ELeave)CDsaMsgQueue;
31 CleanupStack::PushL(self);
32 self->ConstructL(aDirect);
33 CleanupStack::Pop(self);
37 CDsaMsgQueue::CDsaMsgQueue()
40 CDsaMsgQueue::~CDsaMsgQueue()
47 void CDsaMsgQueue::ConstructL(CWsDirectScreenAccess* aDirect)
49 iAborted=new(ELeave) CWsAbortDirect(aDirect,this);
52 void CDsaMsgQueue::Cancel()
54 //purge the queue of data
59 ret = iRecQueue.Receive(&data,sizeof(TInt));
60 }while(ret == KErrNone);
64 TInt CDsaMsgQueue::Send(TInt aData)
66 return iSendQueue.Send(&aData,sizeof(TInt));
69 TInt CDsaMsgQueue::CreateSendQueue()
71 if(iSendQueue.Handle() == 0)
73 return iSendQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess);
81 TInt CDsaMsgQueue::CreateRecQueue()
83 if(iRecQueue.Handle() == 0)
85 return iRecQueue.CreateGlobal(KNullDesC,KMsgQueueLength,sizeof(TInt), EOwnerProcess);
93 RMsgQueueBase* CDsaMsgQueue::SendQueue()
98 RMsgQueueBase* CDsaMsgQueue::RecQueue()
103 void CDsaMsgQueue::Started()
108 void CDsaMsgQueue::Complete()
110 iAborted->Complete(RDirectScreenAccess::ETerminateCancel);
113 void CDsaMsgQueue::CompleteAbort()
115 iAborted->Complete(KErrNone);
118 TInt CDsaMsgQueue::ReceiveData()
121 iRecQueue.Receive(&data,sizeof(TInt));
127 CWsAbortDirect::CWsAbortDirect(CWsDirectScreenAccess* aDirect,CDsaMsgQueue* aParent) : CActive(EDirectAbort), iDirect(aDirect),iParent(aParent)
129 CActiveScheduler::Add(this);
132 CWsAbortDirect::~CWsAbortDirect()
137 void CWsAbortDirect::Started()
139 iStatus=KRequestPending;
140 TRequestStatus& status = iStatus;
141 iParent->RecQueue()->NotifyDataAvailable(status);
145 void CWsAbortDirect::RunL()
147 iParent->ReceiveData();
148 iParent->RecQueue()->CancelDataAvailable();
152 void CWsAbortDirect::DoCancel()
154 iParent->RecQueue()->CancelDataAvailable();
155 if (iStatus==KRequestPending)
161 void CWsAbortDirect::Complete(TInt aReason)
165 TRequestStatus* status=&iStatus;
166 iParent->RecQueue()->CancelDataAvailable();
167 RThread().RequestComplete(status,aReason);
172 /*CWsDirectScreenAccess*/
174 CWsDirectScreenAccess* CWsDirectScreenAccess::NewL(CWsClient* aOwner,TBool aRegionTrackingOnly)
176 CWsDirectScreenAccess* self = new(ELeave) CWsDirectScreenAccess(aOwner);
177 CleanupStack::PushL(self);
178 self->ConstructL(aRegionTrackingOnly);
179 CleanupStack::Pop(self);
183 CWsDirectScreenAccess::~CWsDirectScreenAccess()
186 if (iStatus!=EDirectStatusTimeNotCreated)
188 if (iStatus==EDirectStatusRunning)
190 if (iStatus>=EDirectStatusAborted)
193 WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
194 if(!iRegionTrackingOnly)
196 CScreen* screen = Screen();
197 __ASSERT_DEBUG(screen,Panic(EWsPanicNoScreen));
198 screen->ReleaseDsaScreenDevice();
203 void CWsDirectScreenAccess::ConstructL(TBool aRegionTrackingOnly)
206 iMsgQueue = CDsaMsgQueue::NewL(this);
207 iStatus=EDirectStatusNone;
208 iRegionTrackingOnly = aRegionTrackingOnly;
209 if(!iRegionTrackingOnly)
211 //The Direct Screen Access object is going to be used to draw to the screen so we need to:
212 //1)allocate the buffer
213 //2)initialize the DSA device and surface
214 CScreen* screen = Screen();
215 __ASSERT_DEBUG(screen,Panic(EWsPanicNoScreen));
216 screen->AcquireDsaScreenDeviceL();
220 void CWsDirectScreenAccess::Request(TInt handle)
222 if (iStatus!=EDirectStatusNone)
224 if (iStatus==EDirectStatusCompleted)
230 iWsOwner->PPanic(EWservPanicDirectMisuse);
233 iWsOwner->HandleToClientWindow(handle,&iWin);
235 iWin->GenerateTopRegion(region);
237 //clip the draw region with DSA buffer
238 TRect dsaBuffer(TPoint(0,0), iScreen->DSASizeInPixels());
239 MWsDisplayMapping *dispMap = iScreen->DisplayMapping();
240 TRect dsaBufferInAppSpace;
243 dispMap->MapCoordinates(EDirectScreenAccessSpace,dsaBuffer,EApplicationSpace,dsaBufferInAppSpace);
247 dsaBufferInAppSpace = dsaBuffer;
249 region.ClipRect(dsaBufferInAppSpace);
250 const TInt regionCount=region.Count();
252 SetReply(regionCount);
253 iStatus=EDirectStatusInitialising;
256 void CWsDirectScreenAccess::GetRegion(TInt aNumRects)
259 if (iStatus!=EDirectStatusInitialising)
260 iWsOwner->PPanic(EWservPanicDirectMisuse);
262 STACK_REGION winVisibleRegion, region;
263 iWin->GenerateTopRegion(winVisibleRegion);
264 //clip the draw region with DSA buffer
265 TRect dsaBuffer(TPoint(0,0), iScreen->DSASizeInPixels());
266 MWsDisplayMapping *dispMap = iScreen->DisplayMapping();
267 TRect dsaBufferInAppSpace;
270 dispMap->MapCoordinates(EDirectScreenAccessSpace,dsaBuffer,EApplicationSpace,dsaBufferInAppSpace);
274 dsaBufferInAppSpace = dsaBuffer;
276 region.Copy(winVisibleRegion);
277 region.ClipRect(dsaBufferInAppSpace);
279 const TInt regionCount=region.Count();
280 if (region.Count()==aNumRects)
282 iVisible.Copy(winVisibleRegion);
283 if (iVisible.CheckError())
285 iStatus=EDirectStatusNone;
286 SetReply(KErrNotReady);
290 TInt error = Initiate();
294 TPtrC8 rectList(REINTERPRET_CAST(const TUint8*,region.RectangleList()),region.Count()*sizeof(TRect));
295 CWsClient::ReplyBuf(rectList);
296 iStatus=EDirectStatusRunning;
297 iMsgQueue->Started();
302 iStatus=EDirectStatusNone;
309 SetReply(region.Count());
312 winVisibleRegion.Close();
315 void CWsDirectScreenAccess::Cancel()
321 case EDirectStatusInitialising:
322 iWsOwner->PPanic(EWservPanicDirectMisuse);
324 case EDirectStatusNone:
326 case EDirectStatusRunning:
330 case EDirectStatusCanceling:
332 iMsgQueue->Send(RDirectScreenAccess::ETerminateCancel);
334 case EDirectStatusAbortedWindow:
335 case EDirectStatusAbortedGlobal:
338 case EDirectStatusCompleted:
345 iStatus=EDirectStatusNone;
348 void CWsDirectScreenAccess::Aborted()
352 case EDirectStatusRunning:
355 iStatus=EDirectStatusCanceling;
357 case EDirectStatusAbortedWindow:
358 case EDirectStatusAbortedGlobal:
361 case EDirectStatusCompleted:
362 iStatus=EDirectStatusNone;
365 iWsOwner->PPanic(EWservPanicDirectMisuse);
369 void CWsDirectScreenAccess::AbortNow()
371 if (iStatus!=EDirectStatusRunning)
373 iWsOwner->PPanic(EWservPanicDirectMisuse);
375 SignalAbort(RDirectScreenAccess::ETerminateRegion);
376 TRequestStatus timerStatus;
377 RTimer& timer=CWsTop::Timer();
378 timer.After(timerStatus,400000); //0.4secs
379 User::WaitForRequest(iMsgQueue->Status(),timerStatus);
380 if (timerStatus!=KRequestPending)
388 User::WaitForRequest(timerStatus);
392 void CWsDirectScreenAccess::SignalAbort(RDirectScreenAccess::TTerminationReasons aReason)
394 iAbortReason=aReason;
395 if (iStatus==EDirectStatusAbortedWindow)
397 WS_ASSERT_DEBUG(iAbortReason>RDirectScreenAccess::ETerminateRegion, EWsPanicDirectScreenAccess);
401 if (iStatus!=EDirectStatusRunning)
403 iWsOwner->PPanic(EWservPanicDirectMisuse);
405 iMsgQueue->Send(aReason);
408 void CWsDirectScreenAccess::CancelAbortObject()
410 iMsgQueue->Complete();
412 iStatus=EDirectStatusNone;
417 void CWsDirectScreenAccess::Abort()
419 if ( iStatus == EDirectStatusRunning )
422 if (iMsgQueue->Status()==KRequestPending)
423 iStatus=(iAbortReason<=RDirectScreenAccess::ETerminateRegion ? EDirectStatusAbortedWindow:EDirectStatusAbortedGlobal);
425 iStatus=EDirectStatusCompleted;
426 if (iStatus!=EDirectStatusAbortedWindow)
431 TInt CWsDirectScreenAccess::GetSendQueue()
433 TInt ret = iMsgQueue->CreateSendQueue();
436 iWsOwner->SetResponseHandle(iMsgQueue->SendQueue());
441 TInt CWsDirectScreenAccess::GetRecQueue()
443 TInt ret = iMsgQueue->CreateRecQueue();
446 iWsOwner->SetResponseHandle(iMsgQueue->RecQueue());
451 void CWsDirectScreenAccess::CommandL(TInt aOpcode,const TAny* aCmdData)
453 TWsDirectCmdUnion pData;
457 case EWsDirectOpFree:
460 case EWsDirectOpRequest:
463 case EWsDirectOpInitFailed:
465 if (iStatus!=EDirectStatusInitialising)
467 iWsOwner->PPanic(EWservPanicDirectMisuse);
470 iStatus=EDirectStatusNone;
472 case EWsDirectOpGetRegion:
473 GetRegion(*pData.Int);
475 case EWsDirectOpCancel:
478 case EWsDirectOpGetSendQueue:
481 case EWsDirectOpGetRecQueue:
485 OwnerPanic(EWservPanicOpcode);
490 TInt CWsDirectScreenAccess::Initiate()
492 const TInt err = iWin->AddDSA(*this);
496 iScreen->AddDirect(*this);
500 static TBool RegionsMatch(const TRegion & aOne, const TRegion & aTwo)
502 // Check if the regions have equal areas.
503 const TRect* rect1 = aOne.RectangleList();
505 for(TInt i = 0; i < aOne.Count(); ++i)
507 area1 += (rect1->Width() * rect1->Height());
511 const TRect* rect2 = aTwo.RectangleList();
513 for(TInt i = 0; i < aTwo.Count(); ++i)
515 area2 += (rect2->Width() * rect2->Height());
524 // Check if one region is completely contained within the other.
525 STACK_REGION tempRegion;
526 tempRegion.Copy(aOne);
527 tempRegion.SubRegion(aTwo);
529 const TBool ret(tempRegion.IsEmpty());
535 TBool CWsDirectScreenAccess::IsAbortRequired(const TRegion& aTopVisibleRegion) const
537 return ( iStatus == EDirectStatusRunning ) && !RegionsMatch(aTopVisibleRegion, iVisible);
540 void CWsDirectScreenAccess::Terminate1()
542 WS_ASSERT_DEBUG(!iWin->DSAs().IsEmpty(), EWsPanicDirectScreenAccess);
543 iWin->RemoveDSA(*this);
546 void CWsDirectScreenAccess::Terminate2()
548 iScreen->RemoveDirect(*this);
549 WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
552 void CWsDirectScreenAccess::CorrectScreen()
554 if (iAbortReason<=RDirectScreenAccess::ETerminateRegion)
557 RootWindow()->Invalidate(&iVisible);
560 RootWindow()->InvalidateWholeScreen();
562 WS_ASSERT_DEBUG(!OnQueue(), EWsPanicDirectScreenAccess);
563 iScreen->UpdateDsa();
567 TBool CWsDirectScreenAccess::OnQueue()
569 return iScreen->IsDirectOnQueue(this);