windowing/windowserver/nonnga/CLIENT/RDirect.CPP
changeset 0 5d03bc08d59c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     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 	}