diff -r 000000000000 -r 5d03bc08d59c windowing/windowserver/nonnga/CLIENT/RDirect.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowing/windowserver/nonnga/CLIENT/RDirect.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,504 @@ +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Client side classes for handling direct screen access +// +// + +#include +#include +#include "../SERVER/w32cmd.h" +#include "CLIENT.H" +#include "w32comm.h" +#include + +NONSHARABLE_CLASS(CDsaMsgQueue) : public CActive +{ + public: + CDsaMsgQueue(); + ~CDsaMsgQueue(); + void Request(TRequestStatus* aClientRequest); + TBool Started() { return iStarted;} + TBool Completed(); + void OpenRecQueue(TInt aHandle); + void OpenSendQueue(TInt aHandle); + TInt Send(TInt aData); + RMsgQueueBase& SendQueue() {return iSendQueue; } + RMsgQueueBase& Queue() { return iRecQueue; } + TRequestStatus* Status() { return &iStatus; } + TBool RequestStarted() { return iStarted;} + private: + void DoCancel(); + void RunL(); + void Listen(); + + private: + RMsgQueueBase iRecQueue; + RMsgQueueBase iSendQueue; + TRequestStatus* iClientRequest; + TBool iStarted; + RThread* iServer; +}; + +// +CDsaMsgQueue::CDsaMsgQueue() : CActive(RDirectScreenAccess::EPriorityVeryHigh) + { + CActiveScheduler::Add(this); + } + +CDsaMsgQueue::~CDsaMsgQueue() + { + Cancel(); + iRecQueue.Close(); + iSendQueue.Close(); + } + +TInt CDsaMsgQueue::Send(TInt aData) + { + return iSendQueue.Send(&aData,sizeof(TInt)); + } + +void CDsaMsgQueue::OpenRecQueue(TInt aHandle) + { + iRecQueue.SetHandle(aHandle); +// With RmessagePtr2 compelete using an RHandle the returned handle is already duplicated + } + +void CDsaMsgQueue::OpenSendQueue(TInt aHandle) + { + iSendQueue.SetHandle(aHandle); +// With RmessagePtr2 compelete using an RHandle the returned handle is already duplicated + } + +void CDsaMsgQueue::DoCancel() + { + iRecQueue.CancelDataAvailable(); + TInt ret = KErrNone; + do + { + TInt data = 0; + ret = iRecQueue.Receive(&data,sizeof(TInt)); + }while(ret == KErrNone); + if(iClientRequest) + { + RThread().RequestComplete(iClientRequest,KErrCancel); + } + } + +void CDsaMsgQueue::RunL() + { + // get the data from the msg queue + TInt reason = 0; + iRecQueue.Receive(&reason,sizeof(TInt)); + + if(iClientRequest) + { + // if there is an outstanding client request, complete and pass on the abort reason + User::RequestComplete(iClientRequest,reason); + iClientRequest = NULL; + } + } + +void CDsaMsgQueue::Listen() + { + if(!IsActive()) + { + SetActive(); + iRecQueue.NotifyDataAvailable(iStatus); + } + } + +void CDsaMsgQueue::Request(TRequestStatus* aClientRequest) + { + __ASSERT_ALWAYS(!IsActive(),User::Invariant()); + iClientRequest = aClientRequest; + iStarted = ETrue; + Listen(); + } + +TBool CDsaMsgQueue::Completed() + { + if(iStarted) + { + Send(KErrNone); + iStarted = EFalse; + return ETrue; + } + return EFalse; + } + +// +// RDirectScreenAccess +// + +EXPORT_C RDirectScreenAccess::RDirectScreenAccess() +/** Default constructor. + +Developers should use the other constructor overload instead. */ + { + } + +EXPORT_C RDirectScreenAccess::RDirectScreenAccess(RWsSession& aWs) : MWsClientClass(aWs.iBuffer), iWs(&aWs), iMsgQueue(NULL) +/** C++ constructor with a connected window server session. + +Construct() must be called to complete construction. + +@param aWs Connected session with the window server. */ + { + } + +EXPORT_C TInt RDirectScreenAccess::Construct() +/** Second phase constructor. + +Creates the server side resource and initialises the client's handle to it. + +This function always causes a flush of the window server buffer. + +@return KErrNone if successful, otherwise one of the system wide error codes. +@panic TW32Panic 17 in debug builds if called on an already constructed object.*/ + { + __ASSERT_DEBUG(iWsHandle == KNullHandle, Panic(EW32PanicGraphicDoubleConstruction)); + TInt ret = KErrNone; + if ((ret = iBuffer->WriteReplyWs(EWsClOpCreateDirectScreenAccess)) >= 0) + { + iWsHandle = ret; + TRAP(ret,iMsgQueue = new (ELeave)CDsaMsgQueue); + if(ret == KErrNone) + { + // the servers send queue is the client receive queue + TInt h = WriteReply(EWsDirectOpGetSendQueue); + iMsgQueue->OpenRecQueue(h); + + // servers receive queue is the clients send queue + h = WriteReply(EWsDirectOpGetRecQueue); + iMsgQueue->OpenSendQueue(h); + } + else + { + Close(); + } + } + return(ret); + } + +EXPORT_C TInt RDirectScreenAccess::Construct(TBool /*aRegionTrackingOnly*/) +/** Second phase constructor. +This is not supported in WSERV non NGA. It's available just when NGA is present.*/ + { + return KErrNotSupported; + } + +EXPORT_C TInt RDirectScreenAccess::Request(RRegion*& aRegion,TRequestStatus& aStatus,const RWindowBase& aWindow) +/** Issues a request to the window server for permission to perform direct screen +access on a window. + +Direct access to the screen may be refused due to lack of memory or if the +target window is completely obscured. + +If direct access is allowed, the function passes back a clipping region which +is the part of the screen the caller can draw to. + +When direct screen access must stop, for instance because a dialog is to be +displayed in front of the region where direct screen access is taking place, +the window server completes the request. The recommended way to check for +this is for aStatus to be the request status of an active object that will +be run when the request completes, i.e. if Request() returns KErrNone, call +SetActive(), and in the object's RunL(), you should immediately abort direct +screen access. + +While the DSA is in operation, it is strongly advised that the client should +not make any call to WSERV that will affect the visible area of the window in +which the DSA is taking place. + +When WSERV tells the client that it needs to abort its DSA, it waits to receive +the acknowledgment from the client that it has done so. However, it doesn't wait +for ever, since the client may have entered some long running calculation or even +an infinite loop. So WSERV also waits on a timer: if the timer expires before the +client acknowledges, then WSERV continues; if, later on, WSERV gets notification +from the client that it has aborted the DSA, then WSERV will invalidate the region +in which the DSA was taking place, just in case there had been a conflict between +the DSA and another client. + + +This function always causes a flush of the window server buffer. + +@param aRegion On return, the clipping region that the caller can draw to. +NULL if the function was not successful. +If the target window is invisible or completely covered by other windows +then the region will be empty. +@param aStatus A request status that is set to a completion code by the window +server when direct screen access must stop. +@param aWindow The window that you want to perform the direct screen access +on. There must not already be direct access on this window or a panic occurs. +@return KErrNone if the request was successful, KErrNone with empty region if +none of the window is currently visible, otherwise one of the system wide error codes, +e.g. KErrNoMemory if out of memory. */ + { + __ASSERT_ALWAYS(iMsgQueue,Panic(EW32PanicDirectMisuse)); + + aRegion = NULL; + + // Allocate the memory for the RRegion here so it is simple to back out + // in case of failure + TAny* regionMem = User::Alloc (sizeof (RRegion)); + if (!regionMem) + { + return KErrNoMemory; + } + + TInt ret = WriteReplyInt(aWindow.WsHandle(),EWsDirectOpRequest); + if (ret=0 && ret != KMaxTInt); + if (ret<0) + { + User::Free (regionMem); + delete rectList; + return ret; + } + + aRegion = new (regionMem) RRegion (numRect, rectList); + aStatus = KRequestPending; + iMsgQueue->Request(&aStatus); + iWs->DirectAcessActivation(ETrue); + return KErrNone; + } + +EXPORT_C void RDirectScreenAccess::Completed() +/** Indicates to the window server that you have responded to the completion of +the request status passed to Request(), by stopping direct screen access. */ + { + __ASSERT_ALWAYS(iMsgQueue->Started(),Panic(EW32PanicDirectMisuse)); + if(iMsgQueue->Completed()) + { + iWs->DirectAcessActivation(EFalse); + } + } + +EXPORT_C void RDirectScreenAccess::Cancel() +/** Indicates to the window server that you have finished performing direct screen +access. */ + { + if(iMsgQueue->Started()) + { + Completed(); + } + TInt ret = WriteReply(EWsDirectOpCancel); + if(ret != 0) // the server is sending us some data. + { + iMsgQueue->Queue().CancelDataAvailable(); + TInt data = 0; + iMsgQueue->Queue().ReceiveBlocking(&data,sizeof(TInt)); + } + iMsgQueue->Cancel(); + } + +EXPORT_C void RDirectScreenAccess::Close() +/** Calls Completed() then deletes the server side resource and sets the client's +handle to it to NULL. */ + { + if (iBuffer && iWsHandle) + { + if(iMsgQueue && iMsgQueue->Started()) + { + Completed(); + } + Write(EWsDirectOpFree); + delete iMsgQueue; + iMsgQueue = NULL; + } + iWsHandle = NULL; + } + +// +// CDirectScreenAccess +// + +EXPORT_C CDirectScreenAccess* CDirectScreenAccess::NewL(RWsSession& aWs,CWsScreenDevice& aScreenDevice,RWindowBase& aWin,MDirectScreenAccess& aAbort) +/** Allocates and constructs the object and adds it to the current active scheduler. + +This function always causes a flush of the window server buffer. + +@param aWs A session with the window server. +@param aScreenDevice Specifies the characteristics of the screen device to +draw to. +@param aWin The window to draw to directly. +@param aAbort Defines an AbortNow() and a Restart() function which are both +called on aborting, as part of the RunL(). Restart() is called from an idle +time active object (CIdle). +@return The newly constructed object. */ + { + CDirectScreenAccess* self = new(ELeave) CDirectScreenAccess(aWs,&aScreenDevice,aWin,aAbort); + CleanupStack::PushL(self); + self->ConstructL(aWs,EFalse); //this EFalse has no meaning here, it is used just to comply with the changes in NGA code + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CDirectScreenAccess* CDirectScreenAccess::NewL(RWsSession& /*aWs*/,CWsScreenDevice&/* aScreenDevice*/,RWindowBase&/* aWin*/,MDirectScreenAccess&/*aAbort*/,TBool /*aRegionTrackingOnly*/) +/** This is not supported in WSERV non NGA. It's available just when NGA is present.*/ + { + User::Leave(KErrNotSupported); + return NULL; + } + +CDirectScreenAccess::~CDirectScreenAccess() + { + __ASSERT_ALWAYS(!iAborting,Panic(EW32PanicDirectMisuse)); + Cancel(); + delete iGc; + delete iScreenDevice; + if (iDrawingRegion) + iDrawingRegion->Destroy(); + iDirectAccess.Close(); + delete iRestart; + } + +void CDirectScreenAccess::ConstructL(RWsSession& aWs,TBool /*aRegionTrackingOnly*/) + { + iScreenNumber = iWsScreenDevice->GetScreenNumber(); + + User::LeaveIfError(iDirectAccess.Construct()); + iRestart = CIdle::NewL(RDirectScreenAccess::EPriorityVeryHigh-5); + CActiveScheduler::Add(this); + if (aWs.GetColorModeList(NULL)>1) + iFlags |= EDirectCheckModeChange; + if (iWsScreenDevice->NumScreenModes() == 1) + { + if (iWsScreenDevice->GetRotationsList(0,NULL) == 1) + return; + } + iFlags |= EDirectCheckSizeModeChange; + } + +void CDirectScreenAccess::CreateScreenObjectsL(TDisplayMode aCurrentMode) + { + delete iScreenDevice; + iScreenDevice = NULL; + + iScreenDevice = CFbsScreenDevice::NewL(iScreenNumber,aCurrentMode); + + if (iGc) + iGc->Activate(iScreenDevice); + else + { + User::LeaveIfError(iScreenDevice->CreateContext(iGc)); + if (!(iFlags&EDirectCheckSizeModeChange)) + UpdateSizeAndRotation(iGc); + } + } + +EXPORT_C void CDirectScreenAccess::StartL() +/** Informs the window server that you are going to start direct screen access +and sets up a graphics context with which you can draw to the screen. + +It should also be called to restart direct screen access after Cancel() has +been called to stop it. + +While the DSA is in operation, it is strongly advised that the client should +not make any call to WSERV that will affect the visible area of the window in +which the DSA is taking place. + +When WSERV tells the client that it needs to abort its DSA, it waits to receive +the acknowledgment from the client that it has done so. However, it doesn't wait +for ever, since the client may have entered some long running calculation or even +an infinite loop. So WSERV also waits on a timer: if the timer expires before the +client acknowledges, then WSERV continues; if, later on, WSERV gets notification +from the client that it has aborted the DSA, then WSERV will invalidate the region +in which the DSA was taking place, just in case there had been a conflict between +the DSA and another client. + + +This function always causes a flush of the window server buffer. */ + { + if (iDrawingRegion) + iDrawingRegion->Destroy(); + User::LeaveIfError(iDirectAccess.Request(iDrawingRegion,iStatus,iWindow)); + SetActive(); + if ((iFlags&EDirectCheckModeChange) || iScreenDevice == NULL) + { + TDisplayMode currentDisplayMode = iWsScreenDevice->DisplayMode(); + if (iScreenDevice == NULL || currentDisplayMode != iScreenDevice->DisplayMode()) + { + TRAPD(err,CreateScreenObjectsL(currentDisplayMode)); + if (err != KErrNone) + { + Cancel(); + User::Leave(err); + } + } + } + if (iFlags&EDirectCheckSizeModeChange) + UpdateSizeAndRotation(iGc); + iGc->SetOrigin(iWindow.AbsPosition()); + iDrawingRegion->ClipRect(iScreenSize); + iGc->SetClippingRegion(iDrawingRegion); + } + +TInt CDirectScreenAccess::Restart(TAny* aDirect) //static + { + STATIC_CAST(CDirectScreenAccess*,aDirect)->Restart(); + return(KErrNone); + } + +void CDirectScreenAccess::Restart() + { + iAbort.Restart(iReason); + } + +void CDirectScreenAccess::UpdateSizeAndRotation(CFbsBitGc* aGc) + { + TPixelsAndRotation sizeAndRotation; + iWsScreenDevice->GetDefaultScreenSizeAndRotation(sizeAndRotation); + iScreenSize = sizeAndRotation.iPixelSize; + TSize scale = iWsScreenDevice->GetCurrentScreenModeScale(); + iScreenDevice->SetScalingFactor(iWsScreenDevice->GetDefaultScreenModeOrigin(),scale.iWidth,scale.iHeight,1,1); + if (aGc) + aGc->SetOrientation(sizeAndRotation.iRotation); + } + +void CDirectScreenAccess::RunL() + { + iAborting = ETrue; + iReason = REINTERPRET_CAST(RDirectScreenAccess::TTerminationReasons&,iStatus); + iAbort.AbortNow(iReason); + iAborting = EFalse; + iDirectAccess.Completed(); + iRestart->Start(TCallBack(CDirectScreenAccess::Restart,this)); + } + +void CDirectScreenAccess::DoCancel() + { + iDirectAccess.Cancel(); + }