--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/CLIENT/RDirect.CPP Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,567 @@
+// 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 <e32std.h>
+#include <e32base.h>
+#include "../SERVER/w32cmd.h"
+#include "CLIENT.H"
+#include "w32comm.h"
+#include <e32msgqueue.h>
+
+
+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;
+ }
+
+
+LOCAL_C inline TDeviceOrientation Graphics2DeviceOrientation(CFbsBitGc::TGraphicsOrientation aGraphicsOrientation)
+ {
+ return ((TDeviceOrientation)(1 << aGraphicsOrientation));
+ }
+
+//
+// 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));
+ return Construct(EFalse);
+ }
+
+EXPORT_C TInt RDirectScreenAccess::Construct(TBool aRegionTrackingOnly)
+/** 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.
+
+@param aRegionTrackingOnly ETrue if the DSA is intended to be used for region tracking purposes only,
+EFalse if the DSA will be used to perform actual drawing.
+@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;
+ TWsClientOpcodes requestedOpCode = aRegionTrackingOnly? EWsClOpCreateDirectScreenAccessRegionTrackingOnly : EWsClOpCreateDirectScreenAccess;
+
+ if ((ret = iBuffer->WriteReplyWs(requestedOpCode)) >= 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::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.
+@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<KErrNone)
+ {
+ User::Free (regionMem);
+ return ret;
+ }
+ TRect* rectList = NULL;
+ TRect* newRectList;
+ TInt numRect;
+
+ do
+ {
+ numRect = ret;
+ newRectList = STATIC_CAST(TRect*,User::ReAlloc(rectList,numRect*sizeof(TRect)));
+ if (!newRectList)
+ {
+ Write(EWsDirectOpInitFailed);
+ User::Free (regionMem);
+ delete rectList;
+ return KErrNoMemory;
+ }
+ rectList = newRectList;
+ TPtr8 ptr(REINTERPRET_CAST(TUint8*,rectList),ret*sizeof(TRect));
+ ret = WriteReplyIntP(ret,&ptr,EWsDirectOpGetRegion);
+ } while(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. */
+ {
+ return CDirectScreenAccess::NewL(aWs,aScreenDevice,aWin,aAbort,EFalse);
+ }
+
+EXPORT_C CDirectScreenAccess* CDirectScreenAccess::NewL(RWsSession& aWs,CWsScreenDevice& aScreenDevice,RWindowBase& aWin,MDirectScreenAccess& aAbort,TBool aRegionTrackingOnly)
+/** 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).
+@param aRegionTrackingOnly The screen device and GC are allocated if this is EFalse,
+but not if it is ETrue. Only the DSA region data and updates to that are
+available in the latter case. Creating the screen device will trigger the dsa
+buffer allocationand it is an operation that could fail, should this happen
+the function will leave.
+@return The newly constructed object. */
+ {
+ CDirectScreenAccess* self = new(ELeave) CDirectScreenAccess(aWs,&aScreenDevice,aWin,aAbort);
+ CleanupStack::PushL(self);
+ self->ConstructL(aWs,aRegionTrackingOnly);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+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();
+
+ if(aRegionTrackingOnly)
+ {
+ iFlags |= EDirectRegionTrackingOnly;
+ }
+ User::LeaveIfError(iDirectAccess.Construct(aRegionTrackingOnly));
+
+ 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) && !aRegionTrackingOnly)
+ {
+ return;
+ }
+ }
+ iFlags |= EDirectCheckSizeModeChange;
+ }
+
+void CDirectScreenAccess::CreateScreenObjectsL(TDisplayMode aCurrentMode)
+ {
+ __ASSERT_DEBUG(!(iFlags&EDirectRegionTrackingOnly),Panic(EW32PanicDirectMisuse));
+ 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&EDirectRegionTrackingOnly))
+ {
+ 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);
+ if(!(iFlags&EDirectRegionTrackingOnly))
+ {
+ 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;
+ __ASSERT_ALWAYS(iScreenDevice,Panic(EW32PanicDirectMisuse));
+ iScreenDevice->SetDeviceOrientation(Graphics2DeviceOrientation(sizeAndRotation.iRotation));
+ MDisplayMapping* interface = static_cast<MDisplayMapping*>
+ (iWsScreenDevice->GetInterface(MDisplayMapping::ETypeId));
+
+ if(interface)
+ {
+ TRect appAreaInDsa;
+ interface->MapCoordinates(EApplicationSpace, iScreenSize, EDirectScreenAccessSpace, appAreaInDsa);
+ if(!iDrawingRegion->BoundingRect().IsEmpty())
+ {
+ //no point to set draw origin if draw region is empty
+ //this also indicates the place to draw might be outside DSA buffer
+ iScreenDevice->SetDrawDeviceOffset(appAreaInDsa.iTl);
+ }
+ }
+ }
+
+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();
+ }