1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/windowing/windowserver/nonnga/CLIENT/RDirect.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,504 @@
1.4 +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// Client side classes for handling direct screen access
1.18 +//
1.19 +//
1.20 +
1.21 +#include <e32std.h>
1.22 +#include <e32base.h>
1.23 +#include "../SERVER/w32cmd.h"
1.24 +#include "CLIENT.H"
1.25 +#include "w32comm.h"
1.26 +#include <e32msgqueue.h>
1.27 +
1.28 +NONSHARABLE_CLASS(CDsaMsgQueue) : public CActive
1.29 +{
1.30 + public:
1.31 + CDsaMsgQueue();
1.32 + ~CDsaMsgQueue();
1.33 + void Request(TRequestStatus* aClientRequest);
1.34 + TBool Started() { return iStarted;}
1.35 + TBool Completed();
1.36 + void OpenRecQueue(TInt aHandle);
1.37 + void OpenSendQueue(TInt aHandle);
1.38 + TInt Send(TInt aData);
1.39 + RMsgQueueBase& SendQueue() {return iSendQueue; }
1.40 + RMsgQueueBase& Queue() { return iRecQueue; }
1.41 + TRequestStatus* Status() { return &iStatus; }
1.42 + TBool RequestStarted() { return iStarted;}
1.43 + private:
1.44 + void DoCancel();
1.45 + void RunL();
1.46 + void Listen();
1.47 +
1.48 + private:
1.49 + RMsgQueueBase iRecQueue;
1.50 + RMsgQueueBase iSendQueue;
1.51 + TRequestStatus* iClientRequest;
1.52 + TBool iStarted;
1.53 + RThread* iServer;
1.54 +};
1.55 +
1.56 +//
1.57 +CDsaMsgQueue::CDsaMsgQueue() : CActive(RDirectScreenAccess::EPriorityVeryHigh)
1.58 + {
1.59 + CActiveScheduler::Add(this);
1.60 + }
1.61 +
1.62 +CDsaMsgQueue::~CDsaMsgQueue()
1.63 + {
1.64 + Cancel();
1.65 + iRecQueue.Close();
1.66 + iSendQueue.Close();
1.67 + }
1.68 +
1.69 +TInt CDsaMsgQueue::Send(TInt aData)
1.70 + {
1.71 + return iSendQueue.Send(&aData,sizeof(TInt));
1.72 + }
1.73 +
1.74 +void CDsaMsgQueue::OpenRecQueue(TInt aHandle)
1.75 + {
1.76 + iRecQueue.SetHandle(aHandle);
1.77 +// With RmessagePtr2 compelete using an RHandle the returned handle is already duplicated
1.78 + }
1.79 +
1.80 +void CDsaMsgQueue::OpenSendQueue(TInt aHandle)
1.81 + {
1.82 + iSendQueue.SetHandle(aHandle);
1.83 +// With RmessagePtr2 compelete using an RHandle the returned handle is already duplicated
1.84 + }
1.85 +
1.86 +void CDsaMsgQueue::DoCancel()
1.87 + {
1.88 + iRecQueue.CancelDataAvailable();
1.89 + TInt ret = KErrNone;
1.90 + do
1.91 + {
1.92 + TInt data = 0;
1.93 + ret = iRecQueue.Receive(&data,sizeof(TInt));
1.94 + }while(ret == KErrNone);
1.95 + if(iClientRequest)
1.96 + {
1.97 + RThread().RequestComplete(iClientRequest,KErrCancel);
1.98 + }
1.99 + }
1.100 +
1.101 +void CDsaMsgQueue::RunL()
1.102 + {
1.103 + // get the data from the msg queue
1.104 + TInt reason = 0;
1.105 + iRecQueue.Receive(&reason,sizeof(TInt));
1.106 +
1.107 + if(iClientRequest)
1.108 + {
1.109 + // if there is an outstanding client request, complete and pass on the abort reason
1.110 + User::RequestComplete(iClientRequest,reason);
1.111 + iClientRequest = NULL;
1.112 + }
1.113 + }
1.114 +
1.115 +void CDsaMsgQueue::Listen()
1.116 + {
1.117 + if(!IsActive())
1.118 + {
1.119 + SetActive();
1.120 + iRecQueue.NotifyDataAvailable(iStatus);
1.121 + }
1.122 + }
1.123 +
1.124 +void CDsaMsgQueue::Request(TRequestStatus* aClientRequest)
1.125 + {
1.126 + __ASSERT_ALWAYS(!IsActive(),User::Invariant());
1.127 + iClientRequest = aClientRequest;
1.128 + iStarted = ETrue;
1.129 + Listen();
1.130 + }
1.131 +
1.132 +TBool CDsaMsgQueue::Completed()
1.133 + {
1.134 + if(iStarted)
1.135 + {
1.136 + Send(KErrNone);
1.137 + iStarted = EFalse;
1.138 + return ETrue;
1.139 + }
1.140 + return EFalse;
1.141 + }
1.142 +
1.143 +//
1.144 +// RDirectScreenAccess
1.145 +//
1.146 +
1.147 +EXPORT_C RDirectScreenAccess::RDirectScreenAccess()
1.148 +/** Default constructor.
1.149 +
1.150 +Developers should use the other constructor overload instead. */
1.151 + {
1.152 + }
1.153 +
1.154 +EXPORT_C RDirectScreenAccess::RDirectScreenAccess(RWsSession& aWs) : MWsClientClass(aWs.iBuffer), iWs(&aWs), iMsgQueue(NULL)
1.155 +/** C++ constructor with a connected window server session.
1.156 +
1.157 +Construct() must be called to complete construction.
1.158 +
1.159 +@param aWs Connected session with the window server. */
1.160 + {
1.161 + }
1.162 +
1.163 +EXPORT_C TInt RDirectScreenAccess::Construct()
1.164 +/** Second phase constructor.
1.165 +
1.166 +Creates the server side resource and initialises the client's handle to it.
1.167 +
1.168 +This function always causes a flush of the window server buffer.
1.169 +
1.170 +@return KErrNone if successful, otherwise one of the system wide error codes.
1.171 +@panic TW32Panic 17 in debug builds if called on an already constructed object.*/
1.172 + {
1.173 + __ASSERT_DEBUG(iWsHandle == KNullHandle, Panic(EW32PanicGraphicDoubleConstruction));
1.174 + TInt ret = KErrNone;
1.175 + if ((ret = iBuffer->WriteReplyWs(EWsClOpCreateDirectScreenAccess)) >= 0)
1.176 + {
1.177 + iWsHandle = ret;
1.178 + TRAP(ret,iMsgQueue = new (ELeave)CDsaMsgQueue);
1.179 + if(ret == KErrNone)
1.180 + {
1.181 + // the servers send queue is the client receive queue
1.182 + TInt h = WriteReply(EWsDirectOpGetSendQueue);
1.183 + iMsgQueue->OpenRecQueue(h);
1.184 +
1.185 + // servers receive queue is the clients send queue
1.186 + h = WriteReply(EWsDirectOpGetRecQueue);
1.187 + iMsgQueue->OpenSendQueue(h);
1.188 + }
1.189 + else
1.190 + {
1.191 + Close();
1.192 + }
1.193 + }
1.194 + return(ret);
1.195 + }
1.196 +
1.197 +EXPORT_C TInt RDirectScreenAccess::Construct(TBool /*aRegionTrackingOnly*/)
1.198 +/** Second phase constructor.
1.199 +This is not supported in WSERV non NGA. It's available just when NGA is present.*/
1.200 + {
1.201 + return KErrNotSupported;
1.202 + }
1.203 +
1.204 +EXPORT_C TInt RDirectScreenAccess::Request(RRegion*& aRegion,TRequestStatus& aStatus,const RWindowBase& aWindow)
1.205 +/** Issues a request to the window server for permission to perform direct screen
1.206 +access on a window.
1.207 +
1.208 +Direct access to the screen may be refused due to lack of memory or if the
1.209 +target window is completely obscured.
1.210 +
1.211 +If direct access is allowed, the function passes back a clipping region which
1.212 +is the part of the screen the caller can draw to.
1.213 +
1.214 +When direct screen access must stop, for instance because a dialog is to be
1.215 +displayed in front of the region where direct screen access is taking place,
1.216 +the window server completes the request. The recommended way to check for
1.217 +this is for aStatus to be the request status of an active object that will
1.218 +be run when the request completes, i.e. if Request() returns KErrNone, call
1.219 +SetActive(), and in the object's RunL(), you should immediately abort direct
1.220 +screen access.
1.221 +
1.222 +While the DSA is in operation, it is strongly advised that the client should
1.223 +not make any call to WSERV that will affect the visible area of the window in
1.224 +which the DSA is taking place.
1.225 +
1.226 +When WSERV tells the client that it needs to abort its DSA, it waits to receive
1.227 +the acknowledgment from the client that it has done so. However, it doesn't wait
1.228 +for ever, since the client may have entered some long running calculation or even
1.229 +an infinite loop. So WSERV also waits on a timer: if the timer expires before the
1.230 +client acknowledges, then WSERV continues; if, later on, WSERV gets notification
1.231 +from the client that it has aborted the DSA, then WSERV will invalidate the region
1.232 +in which the DSA was taking place, just in case there had been a conflict between
1.233 +the DSA and another client.
1.234 +
1.235 +
1.236 +This function always causes a flush of the window server buffer.
1.237 +
1.238 +@param aRegion On return, the clipping region that the caller can draw to.
1.239 +NULL if the function was not successful.
1.240 +If the target window is invisible or completely covered by other windows
1.241 +then the region will be empty.
1.242 +@param aStatus A request status that is set to a completion code by the window
1.243 +server when direct screen access must stop.
1.244 +@param aWindow The window that you want to perform the direct screen access
1.245 +on. There must not already be direct access on this window or a panic occurs.
1.246 +@return KErrNone if the request was successful, KErrNone with empty region if
1.247 +none of the window is currently visible, otherwise one of the system wide error codes,
1.248 +e.g. KErrNoMemory if out of memory. */
1.249 + {
1.250 + __ASSERT_ALWAYS(iMsgQueue,Panic(EW32PanicDirectMisuse));
1.251 +
1.252 + aRegion = NULL;
1.253 +
1.254 + // Allocate the memory for the RRegion here so it is simple to back out
1.255 + // in case of failure
1.256 + TAny* regionMem = User::Alloc (sizeof (RRegion));
1.257 + if (!regionMem)
1.258 + {
1.259 + return KErrNoMemory;
1.260 + }
1.261 +
1.262 + TInt ret = WriteReplyInt(aWindow.WsHandle(),EWsDirectOpRequest);
1.263 + if (ret<KErrNone)
1.264 + {
1.265 + User::Free (regionMem);
1.266 + return ret;
1.267 + }
1.268 + TRect* rectList = NULL;
1.269 + TRect* newRectList;
1.270 + TInt numRect;
1.271 +
1.272 + do
1.273 + {
1.274 + numRect = ret;
1.275 + newRectList = STATIC_CAST(TRect*,User::ReAlloc(rectList,numRect*sizeof(TRect)));
1.276 + if (!newRectList)
1.277 + {
1.278 + Write(EWsDirectOpInitFailed);
1.279 + User::Free (regionMem);
1.280 + delete rectList;
1.281 + return KErrNoMemory;
1.282 + }
1.283 + rectList = newRectList;
1.284 + TPtr8 ptr(REINTERPRET_CAST(TUint8*,rectList),ret*sizeof(TRect));
1.285 + ret = WriteReplyIntP(ret,&ptr,EWsDirectOpGetRegion);
1.286 + } while(ret >=0 && ret != KMaxTInt);
1.287 + if (ret<0)
1.288 + {
1.289 + User::Free (regionMem);
1.290 + delete rectList;
1.291 + return ret;
1.292 + }
1.293 +
1.294 + aRegion = new (regionMem) RRegion (numRect, rectList);
1.295 + aStatus = KRequestPending;
1.296 + iMsgQueue->Request(&aStatus);
1.297 + iWs->DirectAcessActivation(ETrue);
1.298 + return KErrNone;
1.299 + }
1.300 +
1.301 +EXPORT_C void RDirectScreenAccess::Completed()
1.302 +/** Indicates to the window server that you have responded to the completion of
1.303 +the request status passed to Request(), by stopping direct screen access. */
1.304 + {
1.305 + __ASSERT_ALWAYS(iMsgQueue->Started(),Panic(EW32PanicDirectMisuse));
1.306 + if(iMsgQueue->Completed())
1.307 + {
1.308 + iWs->DirectAcessActivation(EFalse);
1.309 + }
1.310 + }
1.311 +
1.312 +EXPORT_C void RDirectScreenAccess::Cancel()
1.313 +/** Indicates to the window server that you have finished performing direct screen
1.314 +access. */
1.315 + {
1.316 + if(iMsgQueue->Started())
1.317 + {
1.318 + Completed();
1.319 + }
1.320 + TInt ret = WriteReply(EWsDirectOpCancel);
1.321 + if(ret != 0) // the server is sending us some data.
1.322 + {
1.323 + iMsgQueue->Queue().CancelDataAvailable();
1.324 + TInt data = 0;
1.325 + iMsgQueue->Queue().ReceiveBlocking(&data,sizeof(TInt));
1.326 + }
1.327 + iMsgQueue->Cancel();
1.328 + }
1.329 +
1.330 +EXPORT_C void RDirectScreenAccess::Close()
1.331 +/** Calls Completed() then deletes the server side resource and sets the client's
1.332 +handle to it to NULL. */
1.333 + {
1.334 + if (iBuffer && iWsHandle)
1.335 + {
1.336 + if(iMsgQueue && iMsgQueue->Started())
1.337 + {
1.338 + Completed();
1.339 + }
1.340 + Write(EWsDirectOpFree);
1.341 + delete iMsgQueue;
1.342 + iMsgQueue = NULL;
1.343 + }
1.344 + iWsHandle = NULL;
1.345 + }
1.346 +
1.347 +//
1.348 +// CDirectScreenAccess
1.349 +//
1.350 +
1.351 +EXPORT_C CDirectScreenAccess* CDirectScreenAccess::NewL(RWsSession& aWs,CWsScreenDevice& aScreenDevice,RWindowBase& aWin,MDirectScreenAccess& aAbort)
1.352 +/** Allocates and constructs the object and adds it to the current active scheduler.
1.353 +
1.354 +This function always causes a flush of the window server buffer.
1.355 +
1.356 +@param aWs A session with the window server.
1.357 +@param aScreenDevice Specifies the characteristics of the screen device to
1.358 +draw to.
1.359 +@param aWin The window to draw to directly.
1.360 +@param aAbort Defines an AbortNow() and a Restart() function which are both
1.361 +called on aborting, as part of the RunL(). Restart() is called from an idle
1.362 +time active object (CIdle).
1.363 +@return The newly constructed object. */
1.364 + {
1.365 + CDirectScreenAccess* self = new(ELeave) CDirectScreenAccess(aWs,&aScreenDevice,aWin,aAbort);
1.366 + CleanupStack::PushL(self);
1.367 + self->ConstructL(aWs,EFalse); //this EFalse has no meaning here, it is used just to comply with the changes in NGA code
1.368 + CleanupStack::Pop(self);
1.369 + return self;
1.370 + }
1.371 +
1.372 +EXPORT_C CDirectScreenAccess* CDirectScreenAccess::NewL(RWsSession& /*aWs*/,CWsScreenDevice&/* aScreenDevice*/,RWindowBase&/* aWin*/,MDirectScreenAccess&/*aAbort*/,TBool /*aRegionTrackingOnly*/)
1.373 +/** This is not supported in WSERV non NGA. It's available just when NGA is present.*/
1.374 + {
1.375 + User::Leave(KErrNotSupported);
1.376 + return NULL;
1.377 + }
1.378 +
1.379 +CDirectScreenAccess::~CDirectScreenAccess()
1.380 + {
1.381 + __ASSERT_ALWAYS(!iAborting,Panic(EW32PanicDirectMisuse));
1.382 + Cancel();
1.383 + delete iGc;
1.384 + delete iScreenDevice;
1.385 + if (iDrawingRegion)
1.386 + iDrawingRegion->Destroy();
1.387 + iDirectAccess.Close();
1.388 + delete iRestart;
1.389 + }
1.390 +
1.391 +void CDirectScreenAccess::ConstructL(RWsSession& aWs,TBool /*aRegionTrackingOnly*/)
1.392 + {
1.393 + iScreenNumber = iWsScreenDevice->GetScreenNumber();
1.394 +
1.395 + User::LeaveIfError(iDirectAccess.Construct());
1.396 + iRestart = CIdle::NewL(RDirectScreenAccess::EPriorityVeryHigh-5);
1.397 + CActiveScheduler::Add(this);
1.398 + if (aWs.GetColorModeList(NULL)>1)
1.399 + iFlags |= EDirectCheckModeChange;
1.400 + if (iWsScreenDevice->NumScreenModes() == 1)
1.401 + {
1.402 + if (iWsScreenDevice->GetRotationsList(0,NULL) == 1)
1.403 + return;
1.404 + }
1.405 + iFlags |= EDirectCheckSizeModeChange;
1.406 + }
1.407 +
1.408 +void CDirectScreenAccess::CreateScreenObjectsL(TDisplayMode aCurrentMode)
1.409 + {
1.410 + delete iScreenDevice;
1.411 + iScreenDevice = NULL;
1.412 +
1.413 + iScreenDevice = CFbsScreenDevice::NewL(iScreenNumber,aCurrentMode);
1.414 +
1.415 + if (iGc)
1.416 + iGc->Activate(iScreenDevice);
1.417 + else
1.418 + {
1.419 + User::LeaveIfError(iScreenDevice->CreateContext(iGc));
1.420 + if (!(iFlags&EDirectCheckSizeModeChange))
1.421 + UpdateSizeAndRotation(iGc);
1.422 + }
1.423 + }
1.424 +
1.425 +EXPORT_C void CDirectScreenAccess::StartL()
1.426 +/** Informs the window server that you are going to start direct screen access
1.427 +and sets up a graphics context with which you can draw to the screen.
1.428 +
1.429 +It should also be called to restart direct screen access after Cancel() has
1.430 +been called to stop it.
1.431 +
1.432 +While the DSA is in operation, it is strongly advised that the client should
1.433 +not make any call to WSERV that will affect the visible area of the window in
1.434 +which the DSA is taking place.
1.435 +
1.436 +When WSERV tells the client that it needs to abort its DSA, it waits to receive
1.437 +the acknowledgment from the client that it has done so. However, it doesn't wait
1.438 +for ever, since the client may have entered some long running calculation or even
1.439 +an infinite loop. So WSERV also waits on a timer: if the timer expires before the
1.440 +client acknowledges, then WSERV continues; if, later on, WSERV gets notification
1.441 +from the client that it has aborted the DSA, then WSERV will invalidate the region
1.442 +in which the DSA was taking place, just in case there had been a conflict between
1.443 +the DSA and another client.
1.444 +
1.445 +
1.446 +This function always causes a flush of the window server buffer. */
1.447 + {
1.448 + if (iDrawingRegion)
1.449 + iDrawingRegion->Destroy();
1.450 + User::LeaveIfError(iDirectAccess.Request(iDrawingRegion,iStatus,iWindow));
1.451 + SetActive();
1.452 + if ((iFlags&EDirectCheckModeChange) || iScreenDevice == NULL)
1.453 + {
1.454 + TDisplayMode currentDisplayMode = iWsScreenDevice->DisplayMode();
1.455 + if (iScreenDevice == NULL || currentDisplayMode != iScreenDevice->DisplayMode())
1.456 + {
1.457 + TRAPD(err,CreateScreenObjectsL(currentDisplayMode));
1.458 + if (err != KErrNone)
1.459 + {
1.460 + Cancel();
1.461 + User::Leave(err);
1.462 + }
1.463 + }
1.464 + }
1.465 + if (iFlags&EDirectCheckSizeModeChange)
1.466 + UpdateSizeAndRotation(iGc);
1.467 + iGc->SetOrigin(iWindow.AbsPosition());
1.468 + iDrawingRegion->ClipRect(iScreenSize);
1.469 + iGc->SetClippingRegion(iDrawingRegion);
1.470 + }
1.471 +
1.472 +TInt CDirectScreenAccess::Restart(TAny* aDirect) //static
1.473 + {
1.474 + STATIC_CAST(CDirectScreenAccess*,aDirect)->Restart();
1.475 + return(KErrNone);
1.476 + }
1.477 +
1.478 +void CDirectScreenAccess::Restart()
1.479 + {
1.480 + iAbort.Restart(iReason);
1.481 + }
1.482 +
1.483 +void CDirectScreenAccess::UpdateSizeAndRotation(CFbsBitGc* aGc)
1.484 + {
1.485 + TPixelsAndRotation sizeAndRotation;
1.486 + iWsScreenDevice->GetDefaultScreenSizeAndRotation(sizeAndRotation);
1.487 + iScreenSize = sizeAndRotation.iPixelSize;
1.488 + TSize scale = iWsScreenDevice->GetCurrentScreenModeScale();
1.489 + iScreenDevice->SetScalingFactor(iWsScreenDevice->GetDefaultScreenModeOrigin(),scale.iWidth,scale.iHeight,1,1);
1.490 + if (aGc)
1.491 + aGc->SetOrientation(sizeAndRotation.iRotation);
1.492 + }
1.493 +
1.494 +void CDirectScreenAccess::RunL()
1.495 + {
1.496 + iAborting = ETrue;
1.497 + iReason = REINTERPRET_CAST(RDirectScreenAccess::TTerminationReasons&,iStatus);
1.498 + iAbort.AbortNow(iReason);
1.499 + iAborting = EFalse;
1.500 + iDirectAccess.Completed();
1.501 + iRestart->Start(TCallBack(CDirectScreenAccess::Restart,this));
1.502 + }
1.503 +
1.504 +void CDirectScreenAccess::DoCancel()
1.505 + {
1.506 + iDirectAccess.Cancel();
1.507 + }