|
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". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Client side classes for handling direct screen access |
|
15 // |
|
16 // |
|
17 |
|
18 #include <e32std.h> |
|
19 #include <e32base.h> |
|
20 #include "../SERVER/w32cmd.h" |
|
21 #include "CLIENT.H" |
|
22 #include "w32comm.h" |
|
23 #include <e32msgqueue.h> |
|
24 |
|
25 NONSHARABLE_CLASS(CDsaMsgQueue) : public CActive |
|
26 { |
|
27 public: |
|
28 CDsaMsgQueue(); |
|
29 ~CDsaMsgQueue(); |
|
30 void Request(TRequestStatus* aClientRequest); |
|
31 TBool Started() { return iStarted;} |
|
32 TBool Completed(); |
|
33 void OpenRecQueue(TInt aHandle); |
|
34 void OpenSendQueue(TInt aHandle); |
|
35 TInt Send(TInt aData); |
|
36 RMsgQueueBase& SendQueue() {return iSendQueue; } |
|
37 RMsgQueueBase& Queue() { return iRecQueue; } |
|
38 TRequestStatus* Status() { return &iStatus; } |
|
39 TBool RequestStarted() { return iStarted;} |
|
40 private: |
|
41 void DoCancel(); |
|
42 void RunL(); |
|
43 void Listen(); |
|
44 |
|
45 private: |
|
46 RMsgQueueBase iRecQueue; |
|
47 RMsgQueueBase iSendQueue; |
|
48 TRequestStatus* iClientRequest; |
|
49 TBool iStarted; |
|
50 RThread* iServer; |
|
51 }; |
|
52 |
|
53 // |
|
54 CDsaMsgQueue::CDsaMsgQueue() : CActive(RDirectScreenAccess::EPriorityVeryHigh) |
|
55 { |
|
56 CActiveScheduler::Add(this); |
|
57 } |
|
58 |
|
59 CDsaMsgQueue::~CDsaMsgQueue() |
|
60 { |
|
61 Cancel(); |
|
62 iRecQueue.Close(); |
|
63 iSendQueue.Close(); |
|
64 } |
|
65 |
|
66 TInt CDsaMsgQueue::Send(TInt aData) |
|
67 { |
|
68 return iSendQueue.Send(&aData,sizeof(TInt)); |
|
69 } |
|
70 |
|
71 void CDsaMsgQueue::OpenRecQueue(TInt aHandle) |
|
72 { |
|
73 iRecQueue.SetHandle(aHandle); |
|
74 // With RmessagePtr2 compelete using an RHandle the returned handle is already duplicated |
|
75 } |
|
76 |
|
77 void CDsaMsgQueue::OpenSendQueue(TInt aHandle) |
|
78 { |
|
79 iSendQueue.SetHandle(aHandle); |
|
80 // With RmessagePtr2 compelete using an RHandle the returned handle is already duplicated |
|
81 } |
|
82 |
|
83 void CDsaMsgQueue::DoCancel() |
|
84 { |
|
85 iRecQueue.CancelDataAvailable(); |
|
86 TInt ret = KErrNone; |
|
87 do |
|
88 { |
|
89 TInt data = 0; |
|
90 ret = iRecQueue.Receive(&data,sizeof(TInt)); |
|
91 }while(ret == KErrNone); |
|
92 if(iClientRequest) |
|
93 { |
|
94 RThread().RequestComplete(iClientRequest,KErrCancel); |
|
95 } |
|
96 } |
|
97 |
|
98 void CDsaMsgQueue::RunL() |
|
99 { |
|
100 // get the data from the msg queue |
|
101 TInt reason = 0; |
|
102 iRecQueue.Receive(&reason,sizeof(TInt)); |
|
103 |
|
104 if(iClientRequest) |
|
105 { |
|
106 // if there is an outstanding client request, complete and pass on the abort reason |
|
107 User::RequestComplete(iClientRequest,reason); |
|
108 iClientRequest = NULL; |
|
109 } |
|
110 } |
|
111 |
|
112 void CDsaMsgQueue::Listen() |
|
113 { |
|
114 if(!IsActive()) |
|
115 { |
|
116 SetActive(); |
|
117 iRecQueue.NotifyDataAvailable(iStatus); |
|
118 } |
|
119 } |
|
120 |
|
121 void CDsaMsgQueue::Request(TRequestStatus* aClientRequest) |
|
122 { |
|
123 __ASSERT_ALWAYS(!IsActive(),User::Invariant()); |
|
124 iClientRequest = aClientRequest; |
|
125 iStarted = ETrue; |
|
126 Listen(); |
|
127 } |
|
128 |
|
129 TBool CDsaMsgQueue::Completed() |
|
130 { |
|
131 if(iStarted) |
|
132 { |
|
133 Send(KErrNone); |
|
134 iStarted = EFalse; |
|
135 return ETrue; |
|
136 } |
|
137 return EFalse; |
|
138 } |
|
139 |
|
140 // |
|
141 // RDirectScreenAccess |
|
142 // |
|
143 |
|
144 EXPORT_C RDirectScreenAccess::RDirectScreenAccess() |
|
145 /** Default constructor. |
|
146 |
|
147 Developers should use the other constructor overload instead. */ |
|
148 { |
|
149 } |
|
150 |
|
151 EXPORT_C RDirectScreenAccess::RDirectScreenAccess(RWsSession& aWs) : MWsClientClass(aWs.iBuffer), iWs(&aWs), iMsgQueue(NULL) |
|
152 /** C++ constructor with a connected window server session. |
|
153 |
|
154 Construct() must be called to complete construction. |
|
155 |
|
156 @param aWs Connected session with the window server. */ |
|
157 { |
|
158 } |
|
159 |
|
160 EXPORT_C TInt RDirectScreenAccess::Construct() |
|
161 /** Second phase constructor. |
|
162 |
|
163 Creates the server side resource and initialises the client's handle to it. |
|
164 |
|
165 This function always causes a flush of the window server buffer. |
|
166 |
|
167 @return KErrNone if successful, otherwise one of the system wide error codes. |
|
168 @panic TW32Panic 17 in debug builds if called on an already constructed object.*/ |
|
169 { |
|
170 __ASSERT_DEBUG(iWsHandle == KNullHandle, Panic(EW32PanicGraphicDoubleConstruction)); |
|
171 TInt ret = KErrNone; |
|
172 if ((ret = iBuffer->WriteReplyWs(EWsClOpCreateDirectScreenAccess)) >= 0) |
|
173 { |
|
174 iWsHandle = ret; |
|
175 TRAP(ret,iMsgQueue = new (ELeave)CDsaMsgQueue); |
|
176 if(ret == KErrNone) |
|
177 { |
|
178 // the servers send queue is the client receive queue |
|
179 TInt h = WriteReply(EWsDirectOpGetSendQueue); |
|
180 iMsgQueue->OpenRecQueue(h); |
|
181 |
|
182 // servers receive queue is the clients send queue |
|
183 h = WriteReply(EWsDirectOpGetRecQueue); |
|
184 iMsgQueue->OpenSendQueue(h); |
|
185 } |
|
186 else |
|
187 { |
|
188 Close(); |
|
189 } |
|
190 } |
|
191 return(ret); |
|
192 } |
|
193 |
|
194 EXPORT_C TInt RDirectScreenAccess::Construct(TBool /*aRegionTrackingOnly*/) |
|
195 /** Second phase constructor. |
|
196 This is not supported in WSERV non NGA. It's available just when NGA is present.*/ |
|
197 { |
|
198 return KErrNotSupported; |
|
199 } |
|
200 |
|
201 EXPORT_C TInt RDirectScreenAccess::Request(RRegion*& aRegion,TRequestStatus& aStatus,const RWindowBase& aWindow) |
|
202 /** Issues a request to the window server for permission to perform direct screen |
|
203 access on a window. |
|
204 |
|
205 Direct access to the screen may be refused due to lack of memory or if the |
|
206 target window is completely obscured. |
|
207 |
|
208 If direct access is allowed, the function passes back a clipping region which |
|
209 is the part of the screen the caller can draw to. |
|
210 |
|
211 When direct screen access must stop, for instance because a dialog is to be |
|
212 displayed in front of the region where direct screen access is taking place, |
|
213 the window server completes the request. The recommended way to check for |
|
214 this is for aStatus to be the request status of an active object that will |
|
215 be run when the request completes, i.e. if Request() returns KErrNone, call |
|
216 SetActive(), and in the object's RunL(), you should immediately abort direct |
|
217 screen access. |
|
218 |
|
219 While the DSA is in operation, it is strongly advised that the client should |
|
220 not make any call to WSERV that will affect the visible area of the window in |
|
221 which the DSA is taking place. |
|
222 |
|
223 When WSERV tells the client that it needs to abort its DSA, it waits to receive |
|
224 the acknowledgment from the client that it has done so. However, it doesn't wait |
|
225 for ever, since the client may have entered some long running calculation or even |
|
226 an infinite loop. So WSERV also waits on a timer: if the timer expires before the |
|
227 client acknowledges, then WSERV continues; if, later on, WSERV gets notification |
|
228 from the client that it has aborted the DSA, then WSERV will invalidate the region |
|
229 in which the DSA was taking place, just in case there had been a conflict between |
|
230 the DSA and another client. |
|
231 |
|
232 |
|
233 This function always causes a flush of the window server buffer. |
|
234 |
|
235 @param aRegion On return, the clipping region that the caller can draw to. |
|
236 NULL if the function was not successful. |
|
237 If the target window is invisible or completely covered by other windows |
|
238 then the region will be empty. |
|
239 @param aStatus A request status that is set to a completion code by the window |
|
240 server when direct screen access must stop. |
|
241 @param aWindow The window that you want to perform the direct screen access |
|
242 on. There must not already be direct access on this window or a panic occurs. |
|
243 @return KErrNone if the request was successful, KErrNone with empty region if |
|
244 none of the window is currently visible, otherwise one of the system wide error codes, |
|
245 e.g. KErrNoMemory if out of memory. */ |
|
246 { |
|
247 __ASSERT_ALWAYS(iMsgQueue,Panic(EW32PanicDirectMisuse)); |
|
248 |
|
249 aRegion = NULL; |
|
250 |
|
251 // Allocate the memory for the RRegion here so it is simple to back out |
|
252 // in case of failure |
|
253 TAny* regionMem = User::Alloc (sizeof (RRegion)); |
|
254 if (!regionMem) |
|
255 { |
|
256 return KErrNoMemory; |
|
257 } |
|
258 |
|
259 TInt ret = WriteReplyInt(aWindow.WsHandle(),EWsDirectOpRequest); |
|
260 if (ret<KErrNone) |
|
261 { |
|
262 User::Free (regionMem); |
|
263 return ret; |
|
264 } |
|
265 TRect* rectList = NULL; |
|
266 TRect* newRectList; |
|
267 TInt numRect; |
|
268 |
|
269 do |
|
270 { |
|
271 numRect = ret; |
|
272 newRectList = STATIC_CAST(TRect*,User::ReAlloc(rectList,numRect*sizeof(TRect))); |
|
273 if (!newRectList) |
|
274 { |
|
275 Write(EWsDirectOpInitFailed); |
|
276 User::Free (regionMem); |
|
277 delete rectList; |
|
278 return KErrNoMemory; |
|
279 } |
|
280 rectList = newRectList; |
|
281 TPtr8 ptr(REINTERPRET_CAST(TUint8*,rectList),ret*sizeof(TRect)); |
|
282 ret = WriteReplyIntP(ret,&ptr,EWsDirectOpGetRegion); |
|
283 } while(ret >=0 && ret != KMaxTInt); |
|
284 if (ret<0) |
|
285 { |
|
286 User::Free (regionMem); |
|
287 delete rectList; |
|
288 return ret; |
|
289 } |
|
290 |
|
291 aRegion = new (regionMem) RRegion (numRect, rectList); |
|
292 aStatus = KRequestPending; |
|
293 iMsgQueue->Request(&aStatus); |
|
294 iWs->DirectAcessActivation(ETrue); |
|
295 return KErrNone; |
|
296 } |
|
297 |
|
298 EXPORT_C void RDirectScreenAccess::Completed() |
|
299 /** Indicates to the window server that you have responded to the completion of |
|
300 the request status passed to Request(), by stopping direct screen access. */ |
|
301 { |
|
302 __ASSERT_ALWAYS(iMsgQueue->Started(),Panic(EW32PanicDirectMisuse)); |
|
303 if(iMsgQueue->Completed()) |
|
304 { |
|
305 iWs->DirectAcessActivation(EFalse); |
|
306 } |
|
307 } |
|
308 |
|
309 EXPORT_C void RDirectScreenAccess::Cancel() |
|
310 /** Indicates to the window server that you have finished performing direct screen |
|
311 access. */ |
|
312 { |
|
313 if(iMsgQueue->Started()) |
|
314 { |
|
315 Completed(); |
|
316 } |
|
317 TInt ret = WriteReply(EWsDirectOpCancel); |
|
318 if(ret != 0) // the server is sending us some data. |
|
319 { |
|
320 iMsgQueue->Queue().CancelDataAvailable(); |
|
321 TInt data = 0; |
|
322 iMsgQueue->Queue().ReceiveBlocking(&data,sizeof(TInt)); |
|
323 } |
|
324 iMsgQueue->Cancel(); |
|
325 } |
|
326 |
|
327 EXPORT_C void RDirectScreenAccess::Close() |
|
328 /** Calls Completed() then deletes the server side resource and sets the client's |
|
329 handle to it to NULL. */ |
|
330 { |
|
331 if (iBuffer && iWsHandle) |
|
332 { |
|
333 if(iMsgQueue && iMsgQueue->Started()) |
|
334 { |
|
335 Completed(); |
|
336 } |
|
337 Write(EWsDirectOpFree); |
|
338 delete iMsgQueue; |
|
339 iMsgQueue = NULL; |
|
340 } |
|
341 iWsHandle = NULL; |
|
342 } |
|
343 |
|
344 // |
|
345 // CDirectScreenAccess |
|
346 // |
|
347 |
|
348 EXPORT_C CDirectScreenAccess* CDirectScreenAccess::NewL(RWsSession& aWs,CWsScreenDevice& aScreenDevice,RWindowBase& aWin,MDirectScreenAccess& aAbort) |
|
349 /** Allocates and constructs the object and adds it to the current active scheduler. |
|
350 |
|
351 This function always causes a flush of the window server buffer. |
|
352 |
|
353 @param aWs A session with the window server. |
|
354 @param aScreenDevice Specifies the characteristics of the screen device to |
|
355 draw to. |
|
356 @param aWin The window to draw to directly. |
|
357 @param aAbort Defines an AbortNow() and a Restart() function which are both |
|
358 called on aborting, as part of the RunL(). Restart() is called from an idle |
|
359 time active object (CIdle). |
|
360 @return The newly constructed object. */ |
|
361 { |
|
362 CDirectScreenAccess* self = new(ELeave) CDirectScreenAccess(aWs,&aScreenDevice,aWin,aAbort); |
|
363 CleanupStack::PushL(self); |
|
364 self->ConstructL(aWs,EFalse); //this EFalse has no meaning here, it is used just to comply with the changes in NGA code |
|
365 CleanupStack::Pop(self); |
|
366 return self; |
|
367 } |
|
368 |
|
369 EXPORT_C CDirectScreenAccess* CDirectScreenAccess::NewL(RWsSession& /*aWs*/,CWsScreenDevice&/* aScreenDevice*/,RWindowBase&/* aWin*/,MDirectScreenAccess&/*aAbort*/,TBool /*aRegionTrackingOnly*/) |
|
370 /** This is not supported in WSERV non NGA. It's available just when NGA is present.*/ |
|
371 { |
|
372 User::Leave(KErrNotSupported); |
|
373 return NULL; |
|
374 } |
|
375 |
|
376 CDirectScreenAccess::~CDirectScreenAccess() |
|
377 { |
|
378 __ASSERT_ALWAYS(!iAborting,Panic(EW32PanicDirectMisuse)); |
|
379 Cancel(); |
|
380 delete iGc; |
|
381 delete iScreenDevice; |
|
382 if (iDrawingRegion) |
|
383 iDrawingRegion->Destroy(); |
|
384 iDirectAccess.Close(); |
|
385 delete iRestart; |
|
386 } |
|
387 |
|
388 void CDirectScreenAccess::ConstructL(RWsSession& aWs,TBool /*aRegionTrackingOnly*/) |
|
389 { |
|
390 iScreenNumber = iWsScreenDevice->GetScreenNumber(); |
|
391 |
|
392 User::LeaveIfError(iDirectAccess.Construct()); |
|
393 iRestart = CIdle::NewL(RDirectScreenAccess::EPriorityVeryHigh-5); |
|
394 CActiveScheduler::Add(this); |
|
395 if (aWs.GetColorModeList(NULL)>1) |
|
396 iFlags |= EDirectCheckModeChange; |
|
397 if (iWsScreenDevice->NumScreenModes() == 1) |
|
398 { |
|
399 if (iWsScreenDevice->GetRotationsList(0,NULL) == 1) |
|
400 return; |
|
401 } |
|
402 iFlags |= EDirectCheckSizeModeChange; |
|
403 } |
|
404 |
|
405 void CDirectScreenAccess::CreateScreenObjectsL(TDisplayMode aCurrentMode) |
|
406 { |
|
407 delete iScreenDevice; |
|
408 iScreenDevice = NULL; |
|
409 |
|
410 iScreenDevice = CFbsScreenDevice::NewL(iScreenNumber,aCurrentMode); |
|
411 |
|
412 if (iGc) |
|
413 iGc->Activate(iScreenDevice); |
|
414 else |
|
415 { |
|
416 User::LeaveIfError(iScreenDevice->CreateContext(iGc)); |
|
417 if (!(iFlags&EDirectCheckSizeModeChange)) |
|
418 UpdateSizeAndRotation(iGc); |
|
419 } |
|
420 } |
|
421 |
|
422 EXPORT_C void CDirectScreenAccess::StartL() |
|
423 /** Informs the window server that you are going to start direct screen access |
|
424 and sets up a graphics context with which you can draw to the screen. |
|
425 |
|
426 It should also be called to restart direct screen access after Cancel() has |
|
427 been called to stop it. |
|
428 |
|
429 While the DSA is in operation, it is strongly advised that the client should |
|
430 not make any call to WSERV that will affect the visible area of the window in |
|
431 which the DSA is taking place. |
|
432 |
|
433 When WSERV tells the client that it needs to abort its DSA, it waits to receive |
|
434 the acknowledgment from the client that it has done so. However, it doesn't wait |
|
435 for ever, since the client may have entered some long running calculation or even |
|
436 an infinite loop. So WSERV also waits on a timer: if the timer expires before the |
|
437 client acknowledges, then WSERV continues; if, later on, WSERV gets notification |
|
438 from the client that it has aborted the DSA, then WSERV will invalidate the region |
|
439 in which the DSA was taking place, just in case there had been a conflict between |
|
440 the DSA and another client. |
|
441 |
|
442 |
|
443 This function always causes a flush of the window server buffer. */ |
|
444 { |
|
445 if (iDrawingRegion) |
|
446 iDrawingRegion->Destroy(); |
|
447 User::LeaveIfError(iDirectAccess.Request(iDrawingRegion,iStatus,iWindow)); |
|
448 SetActive(); |
|
449 if ((iFlags&EDirectCheckModeChange) || iScreenDevice == NULL) |
|
450 { |
|
451 TDisplayMode currentDisplayMode = iWsScreenDevice->DisplayMode(); |
|
452 if (iScreenDevice == NULL || currentDisplayMode != iScreenDevice->DisplayMode()) |
|
453 { |
|
454 TRAPD(err,CreateScreenObjectsL(currentDisplayMode)); |
|
455 if (err != KErrNone) |
|
456 { |
|
457 Cancel(); |
|
458 User::Leave(err); |
|
459 } |
|
460 } |
|
461 } |
|
462 if (iFlags&EDirectCheckSizeModeChange) |
|
463 UpdateSizeAndRotation(iGc); |
|
464 iGc->SetOrigin(iWindow.AbsPosition()); |
|
465 iDrawingRegion->ClipRect(iScreenSize); |
|
466 iGc->SetClippingRegion(iDrawingRegion); |
|
467 } |
|
468 |
|
469 TInt CDirectScreenAccess::Restart(TAny* aDirect) //static |
|
470 { |
|
471 STATIC_CAST(CDirectScreenAccess*,aDirect)->Restart(); |
|
472 return(KErrNone); |
|
473 } |
|
474 |
|
475 void CDirectScreenAccess::Restart() |
|
476 { |
|
477 iAbort.Restart(iReason); |
|
478 } |
|
479 |
|
480 void CDirectScreenAccess::UpdateSizeAndRotation(CFbsBitGc* aGc) |
|
481 { |
|
482 TPixelsAndRotation sizeAndRotation; |
|
483 iWsScreenDevice->GetDefaultScreenSizeAndRotation(sizeAndRotation); |
|
484 iScreenSize = sizeAndRotation.iPixelSize; |
|
485 TSize scale = iWsScreenDevice->GetCurrentScreenModeScale(); |
|
486 iScreenDevice->SetScalingFactor(iWsScreenDevice->GetDefaultScreenModeOrigin(),scale.iWidth,scale.iHeight,1,1); |
|
487 if (aGc) |
|
488 aGc->SetOrientation(sizeAndRotation.iRotation); |
|
489 } |
|
490 |
|
491 void CDirectScreenAccess::RunL() |
|
492 { |
|
493 iAborting = ETrue; |
|
494 iReason = REINTERPRET_CAST(RDirectScreenAccess::TTerminationReasons&,iStatus); |
|
495 iAbort.AbortNow(iReason); |
|
496 iAborting = EFalse; |
|
497 iDirectAccess.Completed(); |
|
498 iRestart->Start(TCallBack(CDirectScreenAccess::Restart,this)); |
|
499 } |
|
500 |
|
501 void CDirectScreenAccess::DoCancel() |
|
502 { |
|
503 iDirectAccess.Cancel(); |
|
504 } |