// Copyright (c) 1994-2010 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 handling
// 
//

#include "CLIENT.H"

#include "ANIM.H"
#include "Direct.H"
#include "EVENT.H"
#include "KEYCLICK.H"
#include "server.h"
#include "gc.h"
#include "rootwin.h"
#include "windowgroup.h"
#include "wstop.h"
#include "panics.h"
#include "../CLIENT/w32comm.h"
#include "password.h"
#include "pointer.h"
#include <u32hal.h> // EHalGroupEmulator
#include "WsMemMgr.h"
#include <e32hashtab.h>  // for RHashMap
#include "registeredsurfacemap.h"
#include <graphics/wselement.h>

#include "windowelementset.h"
#include "drawresource.h"

extern CDebugLogBase* wsDebugLog;
_LIT(KWSERVSessionPanicCategory,"WSERV");

GLREF_D TPtr nullDescriptor;

TWsCmdHeaderBase CWsClient::iCurrentCommand;
TBuf8<EClientBufferMaxSize> CWsClient::iCmdBuf;
TInt CWsClient::iReply;
TInt CWsClient::iReplyOffset;
CWsClient* CWsClient::iCurrentClient;
CWsObject* CWsClient::iDestObj;
const TUint8* CWsClient::iNextCmd;

TUint CWsClient::iConnectionId = CDebugLogBase::EDummyConnectionId+1;
CArrayFixFlat<CWsClient::TWsCursorArrayItem>* CWsClient::iSystemPointerCursors = NULL;
TInt CWsClient::iDefaultSystemPointerCursorIndex = 0;		//Negative when there isn't one
CWsPointerCursor* CWsClient::iDefaultSystemPointerCursor;
CWsClient* CWsClient::iSystemPointerCursorListOwner = NULL;
CArrayFixFlat<CWsClient::TWsCursorArrayItem>* CWsClient::iTextCursorArray = NULL;

TKeyArrayFix CWsClient::iCursorKey(_FOFF(CWsClient::TWsCursorArrayItem,iIndex), ECmpTInt);

/**
Used for enforcing the redraw calling convention in emulator builds.
When enabled this will panic any client calling a CWindowGc draw operation outside a 
RWindow::BeginRedraw() / RWindow::EndRedraw() pair (known as non-redraw drawing).

Enable by adding "debug_wserv_exe_EnforceRedrawCallingConvention X" to epoc.ini 
where X is either 0 (zero) for "off" or 1 (one) for "on". 

Then enable globally in WServ AutoFlush by defining __AUTO_FLUSH in ../client/client.h 
or locally by calling RWsSession::SetAutoFlush(ETrue) for a specific client programatically, 
or locally pressing Ctrl-Alt-Shift-F in the emulator.
*/
TBool CWsClient::iDebug_EnforceRedrawCallingConvention = EFalse;

// Security policy stings
static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_WriteDeviceData,ECapabilityWriteDeviceData);
static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_SwEvent,ECapabilitySwEvent);
static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_PowerMgmt,ECapabilityPowerMgmt);

//
// class CWsClient
// 

CWsClient::CWsClient(RThread aClient) : iClient(aClient), iGraphicMessageQueue(this), iInternalFlags(ERemoveKeyCode|EFinishedProcessingCommands)
	{
	iScreen = CWsTop::Screen();
	}

CWsClient::~CWsClient()
	{
	CWsTop::WindowServer()->RemoveAllGraphicDrawers(*this); // deindexes all graphic drawers owned by this client

	delete iTempCustomTextCursor.iCursor;
	FreeSystemPointerCursorList();
	CWsTop::ClientDestroyed(this);
	if (wsDebugLog)
		{
		_LIT(ClientDestuct,"Client %d destructing");
		wsDebugLog->MiscMessage(CDebugLogBase::ELogIntermediate,ClientDestuct, iConnectionHandle);
		}
		
	iInternalFlags |= EClientIsClosing;
	delete iObjectIndex;
	delete iEventQueue;
	delete iRedrawQueue;
	delete iPriorityKeyEvent;
	CWsTop::ClearSurfaceMap(this);

	CWsTop::SessionExited(this);
	iClient.Close();
	}

void CWsClient::CompleteInitializationL()
	{
	iObjectIndex = new(ELeave) CWsObjectIx();
	iObjectIndex->ConstructL();
	
    iEventQueue = new(ELeave) CEventQueue(this);
	iEventQueue->ConstructL();
    
    iRedrawQueue = new(ELeave) CRedrawQueue(this);
	iRedrawQueue->ConstructL();
    
    iPriorityKeyEvent = new(ELeave) CPriorityKey(this);
	
	CWsCliObj::NewL(this);
	
	iComputeMode = RWsSession::EPriorityControlComputeOff;
	
	CWsTop::NewSession(this);
	
#ifdef __WINS__
	TBool halValue = EFalse;
	if (UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty, 
		(TAny*)"debug_wserv_exe_EnforceRedrawCallingConvention", &halValue) == KErrNone)
		{
		iDebug_EnforceRedrawCallingConvention = halValue;
		}
#endif
	
	iInternalFlags |= EIsInitialised;
	}

TBool CWsClient::DebugEnforceRedrawCallingConvention()
	{
	return iDebug_EnforceRedrawCallingConvention;
	}

void CWsClient::StartInitializationL(TUint aConnectionHandle)
	{
	if (wsDebugLog)
		wsDebugLog->NewClient(aConnectionHandle);
	
	if (iObjectIndex)
		PPanic(EWservPanicReInitialise);
	else
		{
		iConnectionHandle = aConnectionHandle;
		CompleteInitializationL();
		}
	}

//
// Convert a handle to object checking it is of the correct type.
//
void CWsClient::HandleToWindow(TInt aHandle,CWsWindowBase** pWin)
	{
	if ((*pWin=(CWsWindowBase* )HandleToObjUntyped(aHandle))==NULL ||
		((*pWin)->Type()!=WS_HANDLE_WINDOW && (*pWin)->Type()!=WS_HANDLE_GROUP_WINDOW))
		PPanic(EWservPanicWindow);
	}

//
// Convert a handle to object checking it is of the correct type.
//
void CWsClient::HandleToClientWindow(TInt aHandle,CWsClientWindow** pWin)
	{
	if ((*pWin=(CWsClientWindow*)HandleToObj(aHandle, WS_HANDLE_WINDOW))==NULL)
		PPanic(EWservPanicWindow);
	}

void CWsClient::CreateNewPointerCursorL(const TWsClCmdCreatePointerCursor &aCmd)
	{
	CWsPointerCursor* pc=new(ELeave) CWsPointerCursor(this);
	CleanupStack::PushL(pc);
	pc->ConstructL(aCmd);
	CleanupStack::Pop();
	}

// Create a new custom text cursor
void CWsClient::StartSetCustomTextCursorL(const TWsClCmdCustomTextCursorData& aCmd)
	{
	if (!iTextCursorArray)
		{
		const TInt textCursorArrayGranularity = 4;
		iTextCursorArray = new(ELeave) CArrayFixFlat<TWsCursorArrayItem>(textCursorArrayGranularity);
		}
		
	TInt arrayIndex = KErrNotFound;
	if (FindCursorArrayItem(iTextCursorArray, aCmd.identifier, arrayIndex))
		User::Leave(KErrAlreadyExists);
	
	delete iTempCustomTextCursor.iCursor;
	iTempCustomTextCursor.iCursor = NULL;
	iTempCustomTextCursor.iCursor = new(ELeave) CWsCustomTextCursor(this, aCmd.alignment);
	
	static_cast<CWsCustomTextCursor*>(iTempCustomTextCursor.iCursor)->ConstructL(aCmd.flags);
	iTempCustomTextCursor.iIndex = aCmd.identifier;
	}

// Add new custom text cursor to global list
void CWsClient::CompleteSetCustomTextCursorL(TInt aError)
	{
	if (aError)
		{
		delete iTempCustomTextCursor.iCursor;
		iTempCustomTextCursor.iCursor = NULL;
		User::Leave(aError);
		}

	TWsCursorArrayItem entry = iTempCustomTextCursor;
	iTempCustomTextCursor.iCursor = NULL;
	CleanupStack::PushL(entry.iCursor);

	TInt arrayIndex;
	if (FindCursorArrayItem(iTextCursorArray, entry.iIndex, arrayIndex))
		User::Leave(KErrAlreadyExists);
	else
		iTextCursorArray->InsertIsqL(entry, iCursorKey);

	CleanupStack::Pop(entry.iCursor);
	}

CWsCustomTextCursor* CWsClient::FindCustomTextCursor(TInt aIdentifier)
	{
	TInt arrayIndex;
	if (!FindCursorArrayItem(iTextCursorArray, aIdentifier, arrayIndex))
		return NULL;

	return TextCursor(arrayIndex);
	}

void CWsClient::CreateNewSpriteL(const TWsClCmdCreateSprite &aCmd)
	{
	CWsSprite* sprite = new(ELeave) CWsSprite(this);
	CleanupStack::PushL(sprite);
	sprite->ConstructL(aCmd);
	CleanupStack::Pop();
	}

void CWsClient::CreateNewBitmapL(const TWsClCmdCreateBitmap &aCmd)
	{
	DWsBitmap* bitmap = new(ELeave) DWsBitmap(this);
	CleanupStack::PushL(bitmap);
	bitmap->ConstructL(aCmd);
	CleanupStack::Pop();
	}

/** Creates a new window.

If the parent is a window group then a new CWsTopClientWindow instance is created. If the parent is
a window then a new CWsClientWindow instance is created.

@param aCmd The command received from the client
@internalComponent
@released
*/
void CWsClient::CreateNewWindowL(const TWsClCmdCreateWindow &aCmd)
	{
	CWsWindowBase* parent;
	HandleToWindow(aCmd.parent,&parent);
	CWsClientWindow* win = NULL;
	TBool deviceIsInvalid = EFalse;
	CScreen* screen = parent->Screen();
	if (parent->WinType()==EWinTypeGroup)
		{
		__ASSERT_DEBUG(!((CWsWindowGroup*)parent)->ScreenDeviceDeleted(),PPanic(EWservPanicGroupWinScreenDeviceDeleted));
		win=new(ELeave) CWsTopClientWindow(this, screen);
		deviceIsInvalid=!((CWsWindowGroup*)parent)->ScreenDeviceValid();
		}
	else
		win=new(ELeave) CWsClientWindow(this, screen);

	CleanupStack::PushL(win);
	win->ConstructL(aCmd,parent,deviceIsInvalid);
	CleanupStack::Pop(win);
	}

void CWsClient::CreateNewWindowGroupL(const TWsClCmdCreateWindowGroup &aCmd)
	{
	CWsWindowGroup::NewL(this, NULL, aCmd); //screen is initialised inside the constructL
	}

void CWsClient::CreateNewAnimDllL(const TWsClCmdUnion &aParams)
	{
	CWsAnimDll* animDll = new(ELeave) CWsAnimDll(this);
	CleanupStack::PushL(animDll);
	animDll->LoadL(BufferTPtr((TText*)(aParams.LoadAnimDll+1),aParams.LoadAnimDll->length));
	CleanupStack::Pop();
	}	

void CWsClient::CreateNewScreenDeviceL(TInt aDefaultScreenNumber, TUint aClientScreenDevicePointer)
	{
	DWsScreenDevice* screenDevice = new(ELeave) DWsScreenDevice(this, aDefaultScreenNumber,aClientScreenDevicePointer);
	CleanupStack::PushL(screenDevice);
	screenDevice->ConstructL();
	CleanupStack::Pop(screenDevice);
	if (iPrimaryScreenDevice==NULL)
		{
		iPrimaryScreenDevice=screenDevice;
		// When client create screen device, change default screen to the one specified.
		// Client should do this immediately after establishing session
		iScreen = iPrimaryScreenDevice->Screen();
		InitialiseScreenDevices();
		}
	}

void CWsClient::InitialiseScreenDevices()
	{
	const TWsObject* ptr = iObjectIndex->FirstObject();
	const TWsObject* end = ptr+iObjectIndex->Length();
	WS_ASSERT_DEBUG(ptr->iObject==NULL, EWsPanicObjectIndexError);
	while(++ptr<end)
		{
		if (ptr->iObject && ptr->iObject->Type()==WS_HANDLE_GROUP_WINDOW)
			{
			CWsWindowGroup* gw = static_cast<CWsWindowGroup*>(ptr->iObject);
			if(!gw->Device())
				gw->SetScreenDevice(iPrimaryScreenDevice);
			}
		}
	}

void CWsClient::CreateNewClickHandlerL(const TUid& aUid)
	{
	CClick* click = new(ELeave) CClick(this);
	CleanupStack::PushL(click);
	click->ConstructL(aUid);
	CleanupStack::Pop(click);
	}

void CWsClient::RequestComplete(TRequestStatus*  &aStatus, TInt aErr)
	{
	Client().RequestComplete(aStatus,aErr);
	}

void CWsClient::PanicCurrentClient(TClientPanic aPanic)
	{
	iCurrentClient->PPanic(aPanic);
	}

void CWsClient::PPanic(TClientPanic aPanic) const
//This function is allowed to leave with out the 'L' convention for special reasons
	{
	SessionPanic(aPanic);
	User::Leave(EPanicLeave);
	}

void CWsClient::SessionPanic(TClientPanic aReason) const
	{
	if (wsDebugLog)
		wsDebugLog->Panic(iConnectionHandle, aReason);
	
	if (!(iInternalFlags&EPanicClientAsSoonAsPossible)) // keep the first error code
		{
		iInternalFlags |= EPanicClientAsSoonAsPossible;
		iPanicReason = aReason;
		}
	}

void CWsClient::SessionTerminate()
	{
	if (wsDebugLog)
		wsDebugLog->Panic(iConnectionHandle, 0);

	const RThread thread=Client();
	RProcess process;
	if (thread.Process(process)==KErrNone)
		{
		process.Terminate(0);
		process.Close();
		}
	}

/**	
Returns the remaining space in the descriptor
*/
TInt CWsClient::ReplyBufSpace() 
	{
	const TInt retVal = iCurrentClient->ClientMessage().GetDesLength(KReplyBufferMessageSlot);
	
	if (iReplyOffset>=0 && retVal>=iReplyOffset)
		return retVal-iReplyOffset;
	else
		return (retVal<0 ? retVal : KErrBadDescriptor);
	}

void CWsClient::ReplyBuf(const TDesC16 &aDes)	// static
	{
	WS_ASSERT_DEBUG(!iCurrentClient->ClientMessage().IsNull(), EWsPanicInvalidMessageHandle);
	
	if(iCurrentClient->ClientMessage().Write(KReplyBufferMessageSlot,aDes,iReplyOffset) != KErrNone)
		PanicCurrentClient(EWservPanicDescriptor);
	
	iReplyOffset += aDes.Length();
	if (wsDebugLog)
		wsDebugLog->ReplyBuf(aDes);
	}

void CWsClient::ReplyBuf(const TDesC8 &aDes)	// static
	{
	WS_ASSERT_DEBUG(!iCurrentClient->ClientMessage().IsNull(), EWsPanicInvalidMessageHandle);
	
	if(iCurrentClient->ClientMessage().Write(KReplyBufferMessageSlot, aDes, iReplyOffset) != KErrNone)
		PanicCurrentClient(EWservPanicDescriptor);
	
	iReplyOffset += aDes.Length();
	if (wsDebugLog)
		wsDebugLog->ReplyBuf(aDes);
	}

void CWsClient::ReplyBuf(const TAny* aSource, TInt aLength)	// static
//
// Send a buffer to the client process.
//
	{
	TPtrC8 src(reinterpret_cast<const TUint8*>(aSource),aLength);
	ReplyBuf(src);
	}

void CWsClient::ReplySize(const TSize &aSize)	// static
	{
	ReplyBuf(&aSize, sizeof(aSize));
	}

void CWsClient::ReplyPoint(const TPoint &aPoint)	// static
	{
	ReplyBuf(&aPoint, sizeof(aPoint));
	}

void CWsClient::ReplyRect(const TRect &aRect)	// static
	{
	ReplyBuf(&aRect, sizeof(aRect));
	}

void CWsClient::SetReply(TInt reply)
	{
	iReply = reply;
	if (wsDebugLog)
		wsDebugLog->Reply(reply);
	}

const TUint8* CWsClient::EndOfCommandBuffer()
	{
	return(iCmdBuf.Ptr()+iCmdBuf.Size());
	}

const TPtrC CWsClient::BufferTPtr(TText *aStart,TInt aLen)
	{
	TPtrC ptr;
	if (!BufferTPtrGc(aStart,aLen,ptr))
		PanicCurrentClient(EWservPanicBufferPtr);
	return(ptr);
	}

TBool CWsClient::BufferTPtrGc(TText* aStart,TInt aLen, TPtrC& aPtr)
	{
	if (iCurrentCommand.iOpcode>0)
		{
		if ((REINTERPRET_CAST(TUint8*,aStart)<iCmdBuf.Ptr()
										|| REINTERPRET_CAST(TUint8*,aStart+aLen)>(iCmdBuf.Ptr()+iCmdBuf.Size())))
			return(EFalse);
		}
	else
		{
		if (aLen>=iCurrentCommand.iCmdLength)
			return(EFalse);
		}
	aPtr.Set(aStart,aLen);
	return(ETrue);
	}

const TPtrC8 CWsClient::BufferTPtr8(TUint8* aStart,TInt aLen)
	{
	if (iCurrentCommand.iOpcode>0 && (REINTERPRET_CAST(TUint8*,aStart)<iCmdBuf.Ptr()
										|| REINTERPRET_CAST(TUint8*,aStart+aLen)>(iCmdBuf.Ptr()+iCmdBuf.Size())))
		PanicCurrentClient(EWservPanicBufferPtr);
		
	return(TPtrC8(aStart,aLen));
	}

/**
Process a command buffer

@internalComponent
@released
*/
void CWsClient::DispatchCommandsInBufL()	// (step #4)
	{		
	if (wsDebugLog)
		{
 		wsDebugLog->CommandBuf(iConnectionHandle);
 		RThread client = Client(); 
 		wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, client.FullName());
		}
	const TUint8* endCmd=iCmdBuf.Ptr()+iCmdBuf.Length();
	do
		{
		const TWsCmdHeader* pCmd=
				reinterpret_cast<const TWsCmdHeader*>(iNextCmd);
		TUint opcode = pCmd->iBase.iOpcode;
		TInt headerLen = sizeof(pCmd->iBase);
		iCurrentCommand = pCmd->iBase;
		
		// For performance reasons the handle is only included
		// if it is different from the previous command. The EWsOpcodeHandle
		// flag indicates whether a new handle has been included in the
		// current command. If not we use the same handle as the previous
		// command.
		if (opcode&EWsOpcodeHandle)
			{
			// Find the WServ object associated with this op code
			opcode &= ~EWsOpcodeHandle;
			iCurrentCommand.iOpcode = reinterpret_cast<TUint16&>(opcode);
			iDestObj=HandleToObjUntyped(pCmd->iDestHandle);
			headerLen = sizeof(*pCmd);
			}
			
		iNextCmd += headerLen;
		const TAny* cmdParams = iNextCmd;
		iNextCmd += pCmd->iBase.iCmdLength;
		if (!iDestObj || iNextCmd>endCmd)		// Invalid handle or Corrupt buffer
			{
			SessionPanic(iDestObj==NULL ? EWservPanicHandle : EWservPanicBuffer);
			iInternalFlags|=EFinishedProcessingCommands;
			break;
			}

		if (iNextCmd==endCmd)
			iInternalFlags|=EFinishedProcessingCommands;
			
		if (wsDebugLog)
			wsDebugLog->Command(iDestObj->Type(), opcode, cmdParams, iDestObj->LogHandle());
		
		// Dispatch the command to the WServ object that will process it
		iDestObj->CommandL(opcode, cmdParams);	// (call #5)
		} 
	while(iNextCmd<endCmd);
	
	}

void CWsClient::DoServiceCommandBuf() // (step #3.1)
	{
	iCurrentClient=this;
	iInternalFlags&=~EFinishedProcessingCommands;
	TRAPD(err, DispatchCommandsInBufL());	// (call #4)
	
#if defined(_DEBUG)
	if (err!=KErrNone && !(iInternalFlags&(EFinishedProcessingCommands|EPanicClientAsSoonAsPossible)))
		SessionPanic(EWservPanicFunctionLeave);
#endif

	if (err<KErrNone)
		SetReply(err);

	if (iInternalFlags&(EFinishedProcessingCommands|EPanicClientAsSoonAsPossible))
		CompleteMessage(iClientMessage,iReply);	// (finish)
	
	iCurrentClient=NULL;
#if defined(_DEBUG)
	User::Heap().Check();
#endif
	}

void CWsClient::ExecuteAsyncClientCommandL(TInt aOpcode, const RMessage2& aMessage)	// (step #3.2)
	{
	switch(aOpcode)
		{
		case EWsClOpEventReady:
			EventReady(aMessage);
			break;
		case EWsClOpPriorityKeyReady:
			PriorityKeyEventReady(aMessage);
			break;
		case EWsClOpRedrawReady:
			RedrawEventReady(aMessage);
			break;
		case EWsClOpGraphicMessageReady:
			iGraphicMessageQueue.EventReady(aMessage);
			break;
		default:
			{
			PPanic(EWservPanicOpcode);
			break;
			}
		}
	}



void CWsClient::ExecuteCommandL(TInt aOpcode, const TAny* aCmdData)	// (step #6)
	{
	TWsClCmdUnion pData;
	pData.any=aCmdData;
	switch(aOpcode)
		{
		case EWsClOpCreateWindowGroup:
			CreateNewWindowGroupL(*pData.CreateWindowGroup);
			break;
		case EWsClOpCreateWindow:
			CreateNewWindowL(*pData.CreateWindow);
			break;
		case EWsClOpCreateGc:
			CWsGc::NewL(this);
			break;
		case EWsClOpCreateAnimDll:
			if (!CheckBuffer(pData.LoadAnimDll->length, KMaxFileName))
				PanicCurrentClient(EWservPanicBufferPtr);
			CreateNewAnimDllL(pData);
			break;
		case EWsClOpCreateGraphic:
			CWsGraphicDrawerObject::NewL(this,pData);
			break;
		case EWsClOpCreateScreenDevice:
			{
			const TInt screenNumber = pData.CreateScreenDevice->screenNumber;
			const TUint clientScreenDevicePointer = pData.CreateScreenDevice->clientScreenDevicePointer;
			if (screenNumber<0 || screenNumber>=CWsTop::NumberOfScreens())
				{
				PPanic(EWservPanicScreenNumber);
				}
			else
				{
				CreateNewScreenDeviceL(screenNumber,clientScreenDevicePointer);
				}
			}
			break;
		case EWsClOpCreateSprite:
			CreateNewSpriteL(*pData.CreateSprite);
			break;
		case EWsClOpCreatePointerCursor:
			CreateNewPointerCursorL(*pData.CreatePointerCursor);
			break;
		case EWsClOpStartSetCustomTextCursor:
			StartSetCustomTextCursorL(*pData.CustomTextCursorData);
			break;
		case EWsClOpCompleteSetCustomTextCursor:
			CompleteSetCustomTextCursorL(*pData.Int);
			break;
		case EWsClOpCreateBitmap:
			CreateNewBitmapL(*pData.CreateBitmap);
			break;
		case EWsClOpCreateDirectScreenAccess:
			CWsDirectScreenAccess::NewL(this,EFalse);
			break;
		case EWsClOpCreateDirectScreenAccessRegionTrackingOnly:
			CWsDirectScreenAccess::NewL(this,ETrue);	//creates a DSA object that will not draw to the screen, but will use just the region tracking functionality
			break;
		case EWsClOpCreateClick:
			CreateNewClickHandlerL(*pData.Uid);
			break;
		case EWsClOpSetHotKey:
			{
			if(!KSecurityPolicy_SwEvent().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetHotKey API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			TWindowServerEvent::SetHotKeyL(*pData.SetHotKey);
			}
			break;
		case EWsClOpClearHotKeys:
			{
			if(!KSecurityPolicy_SwEvent().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::ClearHotKeys API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			TWindowServerEvent::ClearHotKeysL(*pData.UInt);
			}
			break;
		case EWsClOpRestoreDefaultHotKey:
			TWindowServerEvent::ResetDefaultHotKeyL(*pData.UInt);
			break;
		case EWsClOpSetShadowVector:
			PPanic(EWservPanicOpcode); //this op code is deprecated, should never be generated by the client
			break;
		case EWsClOpShadowVector:
			PPanic(EWservPanicOpcode); //this op code is deprecated, should never be generated by the client
			break;
		case EWsClOpSetKeyboardRepeatRate:
			{
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetKeyboardRepeatRate API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			if ((pData.SetKeyboardRepeatRate->initial.Int()<0) || (pData.SetKeyboardRepeatRate->time.Int()<0))
				{
				User::Leave(KErrArgument);
				}
			CKeyboardRepeat::SetRepeatTime(pData.SetKeyboardRepeatRate->initial,pData.SetKeyboardRepeatRate->time);
			}
			break;
		case EWsClOpGetKeyboardRepeatRate:
			{
			SKeyRepeatSettings settings;
			CKeyboardRepeat::GetRepeatTime(settings.iInitialTime,settings.iTime);
			ReplyBuf(&settings,sizeof(settings));
			}
			break;
		case EWsClOpSetDoubleClick:
			{
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetDoubleClick API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			TWsPointer::SetDoubleClick(pData.SetDoubleClick->interval,pData.SetDoubleClick->distance);
			}
			break;
		case EWsClOpGetDoubleClickSettings:
			{
			SDoubleClickSettings settings;
			TWsPointer::GetDoubleClickSettings(settings.iInterval,settings.iDistance);
			ReplyBuf(&settings,sizeof(settings));
			}
			break;
		case EWsClOpEventReady:
			// No need to do anything
			break;
		case EWsClOpGetEvent:
			HandleClientRequestForEventData();
			// Check flag if the group message queue is overflow and has pended messages  
			if (iInternalFlags & EWgMsgQueueOverflow)
				{
				iInternalFlags &= ~EWgMsgQueueOverflow;
				CWsWindowGroup::ReleasePendedMessagesToAllGroups(this);
				}
			break;
		case EWsClOpPurgePointerEvents:
			PurgePointerEvents();
			break;
		case EWsClOpEventReadyCancel:
			CancelClientRequestForEventData();
			break;
		case EWsClOpRedrawReady:
			iInternalFlags&=~EIsPerformingRedrawEvent;
			break;
		case EWsClOpRedrawReadyCancel:
			CancelClientRequestForRedrawEvent();
			break;
		case EWsClOpGetRedraw:
			HandleClientRequestForRedrawData();
			break;
		case EWsClOpPriorityKeyReady:
			// No need to do anything
			break;
		case EWsClOpPriorityKeyReadyCancel:
			CancelClientRequestForPriorityKeyEvent();
			break;
		case EWsClOpGetPriorityKey:
			HandleClientRequestForPriorityKeyData();
			break;
		case EWsClOpNumWindowGroups:
			SetReply(CWsWindowGroup::NumWindowGroups(EFalse,* pData.Int));
			break;
		case EWsClOpNumWindowGroupsAllPriorities:
			SetReply(CWsWindowGroup::NumWindowGroups(ETrue, 0));
			break;
		case EWsClOpNumWindowGroupsOnScreen:
			{
			const TInt screenNumber=pData.NumWinGroups->screenNumber;
			if (screenNumber<0 || screenNumber>=CWsTop::NumberOfScreens())
				PPanic(EWservPanicScreenNumber);
			else
				SetReply(CWsWindowGroup::NumWindowGroupsOnScreen(CWsTop::Screen(screenNumber)->RootWindow()->Child(),(pData.NumWinGroups->priority==EAllPriorities),pData.NumWinGroups->priority));
			}
			break;
		case EWsClOpWindowGroupList:
			{
			const TInt screenNumber=pData.WindowGroupList->screenNumber;
			if (screenNumber<KDummyScreenNumber || screenNumber>=CWsTop::NumberOfScreens())
				PPanic(EWservPanicScreenNumber);
			else
				SetReply(CWsWindowGroup::SendWindowGroupListL(screenNumber,(pData.WindowGroupList->priority==EAllPriorities), pData.WindowGroupList->priority, pData.WindowGroupList->count));
			}
			break;
		case EWsClOpWindowGroupListAllPriorities:
			{
			const TInt screenNumber=pData.WindowGroupList->screenNumber;
			if (screenNumber<KDummyScreenNumber || screenNumber>=CWsTop::NumberOfScreens())
				PPanic(EWservPanicScreenNumber);
			else
				SetReply(CWsWindowGroup::SendWindowGroupListL(screenNumber,ETrue, 0, pData.WindowGroupList->count));
			}
			break;
		case EWsClOpWindowGroupListAndChain:
			SetReply(CWsWindowGroup::SendWindowGroupListAndChainL(EFalse, pData.WindowGroupList->priority, pData.WindowGroupList->count));
			break;
		case EWsClOpWindowGroupListAndChainAllPriorities:
			SetReply(CWsWindowGroup::SendWindowGroupListAndChainL(ETrue, 0, pData.WindowGroupList->count));
			break;
		case EWsClOpGetDefaultOwningWindow:
			{
			const TInt screenNumber = *pData.Int;
			if (screenNumber<KDummyScreenNumber || screenNumber>=CWsTop::NumberOfScreens())
				PPanic(EWservPanicScreenNumber);
			else
				{
				CScreen* screen = (screenNumber ==KDummyScreenNumber) ? iScreen : CWsTop::Screen(screenNumber);
				SetReply(screen->DefaultOwningWindowGroup() ? screen->DefaultOwningWindowGroup()->Identifier():0);
				}
			}
			break;
		case EWsClOpGetFocusWindowGroup:
			{
			const TInt screenNumber = *pData.Int;
			if (screenNumber<KDummyScreenNumber || screenNumber>=CWsTop::NumberOfScreens())
				PPanic(EWservPanicScreenNumber);
			else
				CWsWindowGroup::GetFocusWindowGroupL(screenNumber);
			}
			break;
		case EWsClOpSetWindowGroupOrdinalPosition:
			CWsWindowGroup::WindowGroupFromIdentifierL(pData.SetWindowGroupOrdinalPosition->identifier)->SetOrdinalPosition(pData.SetWindowGroupOrdinalPosition->position);
			break;
		case EWsClOpGetWindowGroupHandle:
			SetReply(CWsWindowGroup::WindowGroupFromIdentifierL(*pData.Int)->ClientHandle());
			break;
		case EWsClOpGetWindowGroupOrdinalPriority:
			SetReply(CWsWindowGroup::WindowGroupFromIdentifierL(*pData.Int)->OrdinalPriority());
			break;
		case EWsClOpGetWindowGroupClientThreadId:
			{
			TThreadId id=CWsWindowGroup::WindowGroupFromIdentifierL(*pData.Int)->WsOwner()->Client().Id();
			ReplyBuf(&id,sizeof(id));
			}
			break;
		case EWsClOpSendEventToWindowGroup:
			{
			CWsWindowGroup* group=CWsWindowGroup::WindowGroupFromIdentifierL(pData.SendEventToWindowGroup->parameter);
			TWsEvent event=pData.SendEventToWindowGroup->event;
			event.SetHandle(group->ClientHandle());
			// Events in enum TEventCode is protected by capabilities
			if (group->WsOwner()!=this && event.Type()>=EEventNull && event.Type()<EEventUser)
				{
				if (event.Type()<EEventPowerMgmt || event.Type()>=EEventReserved)
					{
					if(!KSecurityPolicy_SwEvent().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SendEventToWindowGroup API")))
						User::Leave(KErrPermissionDenied);
					}
				else
					{
					if (!KSecurityPolicy_PowerMgmt().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SendEventToWindowGroup API")))
						User::Leave(KErrPermissionDenied);
					}
				}
			if (event.Type()==EEventKey && event.Key()->iRepeats!=0)
				CKeyboardRepeat::CancelRepeat(NULL);		//Otherwise we will trip an invarient
			if (!group->EventQueue()->QueueEvent(event))
				User::Leave(KErrNoMemory);
			}
			break;
		case EWsClOpSendEventToAllWindowGroup:
		case EWsClOpSendEventToAllWindowGroupPriority:
		case EWsClOpSendEventToOneWindowGroupPerClient:
			{
			TWsEvent event=pData.SendEventToWindowGroup->event;
			if (event.Type()<0)
				User::Leave(KErrArgument);
			if(event.Type()<EEventUser)
				{
				if (event.Type()<EEventPowerMgmt || event.Type()>=EEventReserved)
					{
					if(!KSecurityPolicy_SwEvent().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SendEventToAllWindowGroup API")))
						User::Leave(KErrPermissionDenied);
					}
				else 
					{
					if (!KSecurityPolicy_PowerMgmt().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SendEventToAllWindowGroup API")))
						User::Leave(KErrPermissionDenied);
					}
				}
			if (!CWsWindowGroup::SendEventToAllGroups(aOpcode!=EWsClOpSendEventToAllWindowGroupPriority
													,aOpcode==EWsClOpSendEventToOneWindowGroupPerClient,*pData.SendEventToWindowGroup))
				User::Leave(KErrNoMemory);
			}
			break;
		case EWsClOpSendMessageToWindowGroup:
			{
			CWsWindowGroup* group=CWsWindowGroup::WindowGroupFromIdentifierL(pData.SendMessageToWindowGroup->identifierOrPriority);
			if (group->WsOwner()!=this)
				{
				if (!KSecurityPolicy_SwEvent().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SendMessageToWindowGroup API")))
					{
					User::Leave(KErrPermissionDenied);
					}
				}
			group->QueueMessageL(pData.SendMessageToWindowGroup->uid, pData.SendMessageToWindowGroup->dataLength,* this);
			}
			break;
		case EWsClOpSendMessageToAllWindowGroups:
		case EWsClOpSendMessageToAllWindowGroupsPriority:
			{
			if ((pData.SendMessageToWindowGroup->dataLength<0) || (pData.SendMessageToWindowGroup->dataLength>=(KMaxTInt/2)))
				{
				User::Leave(KErrArgument);
				}
			CWsWindowGroup::SendMessageToAllGroupsL(*this,aOpcode==EWsClOpSendMessageToAllWindowGroups,*pData.SendMessageToWindowGroup);
			}
			break;
		case EWsClOpFetchMessage:
			CWsWindowGroup::WindowGroupFromIdentifierL(pData.FetchMessage->windowGroupIdentifier)->FetchMessageL();
			break;
		case EWsClOpGetWindowGroupNameFromIdentifier:
			ReplyGroupName(CWsWindowGroup::WindowGroupFromIdentifierL(pData.GetWindowGroupNameFromIdentifier->identifier)->GroupName(),pData.GetWindowGroupNameFromIdentifier->maxLength);
			break;
		case EWsClOpFindWindowGroupIdentifier:
			{
			if (pData.FindWindowGroupIdentifier->length<0)
				User::Leave(KErrArgument);
			TPtrC ptr(BufferTPtr((TText*)(pData.FindWindowGroupIdentifier+1),pData.FindWindowGroupIdentifier->length));
			SetReply(CWsWindowGroup::FindWindowGroupL(this, pData.FindWindowGroupIdentifier->identifier,
							pData.FindWindowGroupIdentifier->offset,&ptr,NULL)->Identifier());
			}
			break;
		case EWsClOpFindWindowGroupIdentifierThread:
			SetReply(CWsWindowGroup::FindWindowGroupL(this, pData.FindWindowGroupIdentifierThread->identifier,0,NULL,
											&pData.FindWindowGroupIdentifierThread->threadId)->Identifier());
			break;
		case EWsClOpSetBackgroundColor:
			for(TInt i=0;i<CWsTop::NumberOfScreens();i++)
				{
				CWsTop::Screen(i)->RootWindow()->SetColor(*pData.rgb);
				}
			break;
		case EWsClOpGetBackgroundColor:
			SetReply(iScreen->RootWindow()->BackColor().Internal());
			break;
		case EWsClOpClaimSystemPointerCursorList:
			{
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::ClaimSystemPointerCursorList API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			ClaimSystemPointerCursorListL();
			}
			break;
		case EWsClOpFreeSystemPointerCursorList:
			FreeSystemPointerCursorList();
			break;
		case EWsClOpSetSystemPointerCursor:
			{
			CWsObject* pointercursor = NULL;
			if ((pointercursor=HandleToObj(pData.SetSystemPointerCursor->handle, WS_HANDLE_POINTER_CURSOR))==NULL)
				PPanic(EWservPanicSprite);
			
			SetSystemPointerCursorL(pData.SetSystemPointerCursor->number, (CWsPointerCursor* )pointercursor);
			}
			break;
		case EWsClOpClearSystemPointerCursor:
			ClearSystemPointerCursor(*pData.Int);
			break;
		case EWsClOpSetPointerCursorArea:
			{
			if(KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetPointerCursorArea API")))
				{
				if (!iScreen->IsValidScreenSizeMode(*pData.Int))
					PPanic(EWservPanicScreenModeNumber);
				iScreen->SetPointerCursorArea(pData.SetPointerCursorArea->mode,pData.SetPointerCursorArea->area);
				}
			}
			break;
		case EWsClOpPointerCursorArea:
			if (!iScreen->IsValidScreenSizeMode(*pData.Int))
				PPanic(EWservPanicScreenModeNumber);
			
			ReplyRect(iScreen->GetPointerCursorArea(*pData.Int));
			break;
		case EWsClOpSetPointerCursorMode:
			{
			CWsWindowGroup* focusWinGp=CWsTop::FocusWindowGroup();
			if (focusWinGp && focusWinGp->WsOwner()==this)
				{
				TWsPointer::SetPointerCursorMode(*pData.Mode);
				TWsPointer::UpdatePointerCursor();
				}
			}
			break;
		case EWsClOpSetClientCursorMode :
			{
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetPointerCursorModeIfFocused API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			TWsPointer::SetPointerCursorMode(*pData.Mode);
			TWsPointer::UpdatePointerCursor();
			}
			break;
		case EWsClOpPointerCursorMode:
			SetReply(TWsPointer::PointerCursorMode());
			break;
		case EWsClOpSetDefaultSystemPointerCursor:
			SetDefaultSystemPointerCursor(*pData.Int);
			break;
		case EWsClOpClearDefaultSystemPointerCursor:
			SetDefaultSystemPointerCursor(ENoDefaultSystemPointerCursor);
			break;
		case EWsClOpSetPointerCursorPosition:
			{
			CWsWindowGroup* focusWinGp=CWsTop::FocusWindowGroup();
			if ((!focusWinGp || focusWinGp->WsOwner()!=this)&&
				(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetPointerCursorPosition API"))))
				{
				User::Leave(KErrPermissionDenied);
				}
			TWsPointer::SetPointerCursorPos(*pData.Point);
			}
			break;
		case EWsClOpPointerCursorPosition:
			ReplyPoint(TWsPointer::PointerCursorPos());
			break;
		case EWsClOpSetModifierState:
			{
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetModifierState API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			TWindowServerEvent::SetModifierState(pData.SetModifierState->modifier,pData.SetModifierState->state);
			}
			break;
		case EWsClOpGetModifierState:
			SetReply(TWindowServerEvent::GetModifierState());
			break;
		case EWsClOpHeapCount:
			SetReply(CWsMemoryManager::Static()->Count());
			break;
 		case EWsClOpDebugInfo:
			DebugInfoL(pData.DebugInfo->iFunction,pData.DebugInfo->iParam,EFalse);
 			break;
 		case EWsClOpDebugInfoReplyBuf:
			DebugInfoL(pData.DebugInfo->iFunction,pData.DebugInfo->iParam,ETrue);
 			break;
		case EWsClOpResourceCount:
			SetReply(iObjectIndex->Count());
			break;
		case EWsClOpHeapSetFail:
			{
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::HeapSetFail API")))
				{
				PPanic(EWservPanicPermissionDenied);
				}
#if !defined(_DEBUG)
			if (pData.HeapSetFail->type!=RHeap::ENone)
				TWindowServerEvent::NotifyOom();
#endif
			// if there is a memory manager and we are making the allocator fail next or 
			// deteministic we want to make sure we test both when the memory manager
			// succeeds and fails in allocating after freeing up memory. we do that by
			// remapping the rate and explicitly telling the memory manager to fail:
			// requested rate  | fail on retry, actual rate
			//        1        |    true      ,    1
			//        2        |    false     ,    1
			//        3        |    true      ,    2
			CWsMemoryManager* memoryManager = NULL;
			TInt rate = pData.HeapSetFail->value;
			TBool memoryManagerRetryFail = EFalse;
			if((pData.HeapSetFail->type == RAllocator::EFailNext || pData.HeapSetFail->type == RAllocator::EDeterministic))
				{
				memoryManager = CWsMemoryManager::Static();
				if(memoryManager)
					{
					memoryManagerRetryFail = (rate % 2 == 1);
					rate = rate / 2 + (memoryManagerRetryFail ? 1 : 0);
					}
				}

			switch (pData.HeapSetFail->type)
				{	//This log message means you can safely ignore the allocation failures in between
					//see CWindowServer::ReleaseMemory()
				case RAllocator::ENone:
					RDebug::Printf("WSERV Heap: __DbgSetAllocFail() <<<ENone");
					break;
				case RAllocator::EReset:
					RDebug::Printf("WSERV Heap: __DbgSetAllocFail() <<<EReset");
					break;
				default:	
					if (memoryManagerRetryFail)
						RDebug::Printf("WSERV Heap: Memory Manager set to fail on retry");
					RDebug::Printf("WSERV Heap: __DbgSetAllocFail(EUser,%i,%i)>>>", pData.HeapSetFail->type, rate);
					break;
				}

			if (memoryManager && memoryManagerRetryFail)
				memoryManager->SetFailNextRetry();
			
			if (pData.HeapSetFail->burst >= 0)
				User::__DbgSetBurstAllocFail(RHeap::EUser, pData.HeapSetFail->type, rate, pData.HeapSetFail->burst);
			else
				User::__DbgSetAllocFail(RHeap::EUser, pData.HeapSetFail->type, rate);
			break;
			}
		case EWsClOpRawEvent:
			{
			if(!KSecurityPolicy_SwEvent().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SimulateRawEvent API")))
				{
				PPanic(EWservPanicPermissionDenied);
				}
			TRawEvent event(*pData.RawEvent);
			if (TWsPointer::PreProcessDriverEvent(event))
				TWindowServerEvent::ProcessRawEvent(event);
			}
			break;
		case EWsClOpKeyEvent:
			{
			if(!KSecurityPolicy_SwEvent().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SimulateKeyEvent API")))
				{
				PPanic(EWservPanicPermissionDenied);
				}
			TWindowServerEvent::ProcessKeyEvent(*pData.KeyEvent,0);
			}
			break;
		case EWsClOpLogMessage:
			if (wsDebugLog)
				{
				if (CheckBuffer(*pData.Int, KLogMessageLength))
					wsDebugLog->MiscMessage(CDebugLogBase::ELogImportant,BufferTPtr((TText* )(pData.Int+1),*pData.Int),0);
				}
			break;
		case EWsClOpPasswordEntered:
			CWsPassword::PasswordEntered(this);
			break;
		case EWsClOpComputeMode:
			SetComputeMode(*pData.ComputeMode);
			break;
		case EWsClOpSendOffEventsToShell:
			{
			if(!KSecurityPolicy_PowerMgmt().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::RequestOffEvents API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			SetReply(CWsTop::SetSendOffEventsToShell(this,*pData.OffEventsToShell));
			}
			break;
		case EWsClOpGetDefModeMaxNumColors:
			{
			SDefModeMaxNumColors colors;
			const TInt screenNumber = *pData.Int;
			if (screenNumber<KDummyScreenNumber || screenNumber>=CWsTop::NumberOfScreens())
				PPanic(EWservPanicScreenNumber);
			else
				{
				CScreen* screen = (screenNumber==KDummyScreenNumber)?iScreen:CWsTop::Screen(screenNumber);
				screen->MaxNumColors(colors.iColors,colors.iGrays);
				colors.iDisplayMode=screen->FirstDefaultDisplayMode();
				}
			ReplyBuf(&colors,sizeof(colors));
			}
			break;
		case EWsClOpGetColorModeList:
			{
			const TInt screenNumber = *pData.Int;
			if (screenNumber<KDummyScreenNumber || screenNumber>=CWsTop::NumberOfScreens())
				PPanic(EWservPanicScreenNumber);
			else
				SetReply((screenNumber==KDummyScreenNumber) ? iScreen->ColorModesFlag() : CWsTop::Screen(screenNumber)->ColorModesFlag());
			}
			break;
		case EWsClOpSetDefaultFadingParams:
			{
			if(KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetDefaultFadingParameters API")))
				{
				iScreen->SetFadingParams(WservEncoding::ExtractFirst8BitValue(*pData.UInt),WservEncoding::ExtractSecond8BitValue(*pData.UInt));
				}
			}
			break;
		case EWsClOpPrepareForSwitchOff:
			{
			if(KSecurityPolicy_PowerMgmt().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::PrepareForSwitchOff API")))
				{
				}
			}
			break;
		case EWsClOpSetFaded:
			{
			// Deprecated - retained for BC with applications that retrieve the fade count
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetSystemFaded API")))
				User::Leave(KErrPermissionDenied);

			TUint8 blackMap;
			TUint8 whiteMap;
			if (pData.SetSystemFaded->UseDefaultMap())
				iScreen->GetFadingParams(blackMap,whiteMap);
			else
				pData.SetSystemFaded->GetFadingParams(blackMap,whiteMap);
			
			iScreen->RootWindow()->SetSystemFaded(pData.SetSystemFaded->Faded(),blackMap,whiteMap);
			}
		break;
		case EWsClOpLogCommand:
			CWsTop::LogCommand(*pData.LogCommand);
			break;
#if defined(__WINS__)
		case EWsClOpRemoveKeyCode:
			iInternalFlags&=~ERemoveKeyCode;
			if (*pData.Bool)
				iInternalFlags|=ERemoveKeyCode;
			break;
		case EWsClOpSimulateXyInput:
			TWsPointer::SetXyInputType(static_cast<TXYInputType>(*pData.XyInput));
			break;
#endif
		case EWsClOpNoFlickerFree:
			PPanic(EWservPanicOpcode); //not supported anymore
			break;
		case EWsClOpSetFocusScreen:
			{
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetFocusScreen API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			TInt focusScreen=*pData.Int;
			if (focusScreen>=0 && focusScreen<CWsTop::NumberOfScreens())
				SetReply(CWsTop::SetCurrentFocusScreen(focusScreen));
			else
				SessionPanic(EWservPanicScreenNumber);
			break;
			}
		case EWsClOpGetFocusScreen:
			SetReply(CWsTop::CurrentFocusScreen()->ScreenNumber());
			break;
		case EWsClOpGetNumberOfScreens:
			SetReply(CWsTop::NumberOfScreens());
			break;
		case EWsClOpClearAllRedrawStores:
			CWsTop::ClearAllRedrawStores();
			break;
		case EWsClOpGetGraphicMessage:
			iGraphicMessageQueue.GetGraphicMessage();
			break;
		case EWsClOpGraphicMessageCancel:
			iGraphicMessageQueue.CancelRead();
			break;
		case EWsClOpGraphicAbortMessage:
			iGraphicMessageQueue.AbortMessage(*pData.Int);
			break;
		case EWsClOpGraphicFetchHeaderMessage:
			SetReply(iGraphicMessageQueue.TopClientHandle());
			break;
		case EWsClOpRegisterSurface:
			SetReply(RegisterSurface(pData));
			break;
		case EWsClOpUnregisterSurface:
			UnregisterSurface(pData);
			break;
		case EWsClOpSetCloseProximityThresholds:
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),
					__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetCloseProximityThresholds")))
				{
				User::Leave(KErrPermissionDenied);
				}
			SetReply(TWsPointer::SetCloseProximityThresholds(pData.ZThresholdPair->enterThreshold,
															 pData.ZThresholdPair->exitThreshold));
			break;
		case EWsClOpSetHighPressureThresholds:
			if(!KSecurityPolicy_WriteDeviceData().CheckPolicy(ClientMessage(),
					__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::SetHighPressureThresholds")))
				{
				User::Leave(KErrPermissionDenied);
				}
			SetReply(TWsPointer::SetHighPressureThresholds(pData.ZThresholdPair->enterThreshold,
					 									   pData.ZThresholdPair->exitThreshold));
			break;
		case EWsClOpGetEnterCloseProximityThreshold:
			SetReply(TWsPointer::GetEnterCloseProximityThreshold());
			break;
		case EWsClOpGetExitCloseProximityThreshold:
			SetReply(TWsPointer::GetExitCloseProximityThreshold());
			break;
		case EWsClOpGetEnterHighPressureThreshold:
			SetReply(TWsPointer::GetEnterHighPressureThreshold());
			break;
		case EWsClOpGetExitHighPressureThreshold:
			SetReply(TWsPointer::GetExitHighPressureThreshold());
			break;
		case EWsClOpCreateDrawableSource:
			CreateDrawableSourceL(*pData.CreateDrawableSource);
			break;
		default:
			PPanic(EWservPanicOpcode);
			break;
		}
	}
/**	Debug information accessor.
 * 	
 * 
 **/
void CWsClient::DebugInfoL(TInt aFunction, TInt aParam, TBool aHasReplyBuf) const
	{
	if (aFunction & EWsDebugClassMask)
		SetReply(DebugInfoClassifiedL(aFunction,aParam,aHasReplyBuf));
	else
		DebugInfoUnclassifiedL(aFunction,aParam,aHasReplyBuf);
	}

/**	A wide variety of generally unconnected debug enquiries.
 * 
 * 
 **/
void CWsClient::DebugInfoUnclassifiedL(TInt aFunction, TInt aParam, TBool aHasReplyBuf) const
	{
	switch(aFunction)
		{
		case EWsDebugInfoHeap:
			if (aHasReplyBuf)
				{
				TWsDebugHeapInfo heapInfo;
				RHeap& heap=User::Heap();
				heapInfo.iCount=heap.AllocSize(heapInfo.iTotal);
				heapInfo.iAvailable=heap.Available(heapInfo.iLargestAvailable);
				ReplyBuf(&heapInfo,sizeof(heapInfo));
				}
			SetReply(KErrArgument);
			break;
		case EWsDebugSetCheckHeapOnDisconnectClient:
			if (!KSecurityPolicy_PowerMgmt().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::DebugInfo API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			CWsTop::SetCheckHeapOnDisconnectClient(this);
			break;
		case EWsDebugSetCheckHeapOnDisconnectMode:
			if (!KSecurityPolicy_PowerMgmt().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWsSession::DebugInfo API")))
				{
				User::Leave(KErrPermissionDenied);
				}
			CWsTop::SetCheckHeapOnDisconnectMode(STATIC_CAST(TWsCheckHeapOnDisconnectMode,aParam));
			break;
		case EWsDebugFetchCheckHeapResult:
			SetReply(CWsTop::FetchCheckHeapResult());
			break;
		case EWsDebugSetEventQueueTest:
			CWsWindowGroup::SetEventQueueTestState(aParam);
			break;
		default:
			SetReply(KErrNotSupported);
			break;
		}
	}
	
/**	Selects a debug function based on the class of debug query.
 * 
 * 
 **/
TInt CWsClient::DebugInfoClassifiedL(TInt aFunction, TInt aParam, TBool aHasReplyBuf) const
	{//Duplicating the meanings of Classified... this would be a good place for a security check
	//first part of param is always screen number
	TInt buffSpace=aHasReplyBuf?ReplyBufSpace():0;
	if (buffSpace<0)
		return (buffSpace);
		
	const TInt screenNumber = (aParam&EWsDebugArgScreenMask)>>EWsDebugArgScreenShift;
	const TInt functionClass = (aFunction&EWsDebugClassMask);
	CScreen* screen = NULL;
	if (functionClass<EWsDebugClassNonScreen)
		{
		if (screenNumber<0 || screenNumber>=CWsTop::NumberOfScreens())
			return (KErrArgument);

		screen = CWsTop::Screen(screenNumber);
		}
	WS_ASSERT_DEBUG(screen, EWsPanicNoScreen);
	switch (aFunction&EWsDebugClassMask)
		{
		case EWsDebugClassScreenUiElement:
			return DebugInfoScreenUiL(aFunction,aParam,buffSpace,*screen);
		case EWsDebugClassScreenElementSet:
			return DebugInfoScreenElementSetL(aFunction, aParam, buffSpace, *screen);
		case EWsDebugClassElementSetWindow:
			return DebugInfoElementSetWindowL(aFunction, aParam, buffSpace, *screen);
		case EWsDebugClassElementSetElement:
			return DebugInfoElementSetElementL(aFunction, aParam, buffSpace, *screen);

		case EWsDebugClassClientWindow:
		default:
			return (KErrNotSupported);
		}
	}

/**	Returns debug info about the UIElement entries for a screen.
 * 	This describes the general state or size of the element set.
 * 	It is indexed via screen num, and optionally element index.
 * 	Element index MUST BE 0 when not required.
 * 	@return size of buffer required or error code.
 **/
TInt CWsClient::DebugInfoScreenUiL(TInt aFunction, TInt /* aParam */, TInt aReplyBufSize, CScreen& aScreen) const
	{
	switch(aFunction)
		{
		case EWsDebugGetFastpathMode:
			{
			// obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
			return KErrNotSupported;
			}
			
		case EWsDebugSetFastpathMode:
			{
            // obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
            return KErrNotSupported;
			}
			
		case EWsDebugGetUIElementInfoList:
			{
            // obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
            return KErrNotSupported;
			}
			
		case EWsDebugGetUIElementBase:
			{
            // obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
            return KErrNotSupported;
			}

		case EWsDebugGetUIElementIds:
			{
            // obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
            return KErrNotSupported;
			}

		case EWsDebugGetSceneElementIdOrder:
			{
            // obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
            return KErrNotSupported;
			}
		case EWsDebugSetFastpathTestMode:
			{
            // obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
            return KErrNotSupported;
			}
			
		case EWsDebugSetFastpathOomMode:
			{
            // obsolete through preq2669
            WS_ASSERT_DEBUG(EFalse, EWsPanicDrawCommandsInvalidState);
            return KErrNotSupported;
			}
		case EWsDebugGetUIElementConfig:
			{
			return DebugReturnConfig(aReplyBufSize,&aScreen.UiElement(),0);

			}
		default:
			return (KErrNotSupported);
		}
	}

/**	Returns debug info about the CWindowElementSet entry for a screen.
 * 	This describes the general state or size of the element set
 * 	It is indexed via screen num.
 * 	@return size of buffer required or error code.
 **/
TInt CWsClient::DebugInfoScreenElementSetL(TInt aFunction, TInt /*aParam*/, TInt aReplyBufSize, const CScreen& aScreen) const
	{
	const CWindowElementSet& elementSet = aScreen.WindowElements();
	switch (aFunction)
		{
		case EWsDebugSerialSurfacesUpdated:
			return 0;

		case EWsDebugSurfaceWindowList:
			{
			TInt outSize = elementSet.Count() * sizeof(TWsDebugWindowId);
			if (outSize<=aReplyBufSize)
				{//can stream, so I shall!
				for (TInt index = 0; index < elementSet.Count(); index++)
					{
					const CWsClientWindow& win = *elementSet.DebugWindowAt(index);
					TWsDebugWindowId id=
						{
						win.ClientHandle(), 0
						};
					if (win.WsOwner()!=this)
						id.iOtherGroupId=win.WinGroup()->Identifier();
					ReplyBuf(&id, sizeof(id));
					}
				}
			return outSize;
			}
		default:
			return (KErrNotSupported);

		}
	}

/**	Returns debug info about a CWindowElement entry.
 * 	This describes the window or the background element(s)
 * 	It is indexed via screen num, and index in elementset.
 * 	@return size of buffer required or error code.
 **/
TInt CWsClient::DebugInfoElementSetWindowL(TInt aFunction, TInt aParam,
		TInt aReplyBufSize, const CScreen& aScreen) const
	{
	const CWindowElementSet& elementSet = aScreen.WindowElements();
	TUint winIndex = (aParam & EWsDebugArgWindowMask) >> EWsDebugArgWindowShift;
	const TAttributes* winElement = elementSet.DebugBackgroundAt(winIndex);
	if (winElement == NULL)
		{
		return KErrArgument;
		}

	MWsElement* backElement = winElement->iElement;
	TInt placedCount = elementSet.DebugPlacedCountAt(winIndex);
	switch (aFunction)
		{
		case EWsDebugElementIdList:
			{
			TInt retVal = (placedCount + 1) * sizeof(MWsElement*);
			if (retVal<aReplyBufSize)
				{
				ReplyBuf(&backElement, sizeof(MWsElement*));
				for (TInt index=0; index<placedCount; index++)
					ReplyBuf(&elementSet.DebugPlacedAt(winIndex, index)->iElement, sizeof(MWsElement*));
				}
			return retVal;
			}
		case EWsDebugBackgroundConfig:
			if (backElement == NULL)
				return KErrNotFound;
			else
				return DebugReturnConfig(aReplyBufSize, backElement,
						winElement->DebugFlags());
		case EWsDebugBackgroundBase:
			if (backElement == NULL)
				return KErrNotFound;
			else
				return DebugReturnBase(aReplyBufSize, backElement);
		case EWsDebugBackgroundFlags:
			return DebugReturnFlags(aReplyBufSize, backElement,
					winElement->DebugFlags());
		default:
			return KErrNotSupported;
		//This method can also be extended to return region and state information from the associated window
		}
	}

/**	Returns debug info about a placed element.
 * 	It is indexed via screen num, index in elementset, and index in placed element array.
 * 	@return size of buffer required or error code.
 **/
TInt CWsClient::DebugInfoElementSetElementL(TInt aFunction, TInt aParam,
		TInt aReplyBufSize, const CScreen& aScreen) const
	{
	const CWindowElementSet& elementSet = aScreen.WindowElements();
	TUint winIndex = (aParam & EWsDebugArgWindowMask) >> EWsDebugArgWindowShift;
	TUint placeIndex = (aParam & EWsDebugArgElementMask) >> EWsDebugArgElementShift;
	const TAttributes* placedElement = elementSet.DebugPlacedAt(winIndex, placeIndex);
	if (placedElement == NULL)
		{
		return KErrArgument;
		}

	MWsElement* element = placedElement->iElement;
	if (element == NULL)
		{
		return KErrNotFound;
		}

	switch (aFunction)
		{
		case EWsDebugPlacedConfig:
			return DebugReturnConfig(aReplyBufSize, element,
					placedElement->DebugFlags());
		case EWsDebugPlacedBase:
			return DebugReturnBase(aReplyBufSize, element);
		case EWsDebugPlacedFlags:
			return DebugReturnFlags(aReplyBufSize, element,
					placedElement->DebugFlags());
		default:
			return KErrNotSupported;
		}
	}

/**	Returns a filled in TSurfaceConfiguration from an MWsElement.
 * 	Data is usually copied if the buffer is big enough
 * 	@return the size of buffer required, or zero if the buffer is acceptable
 **/
TInt CWsClient::DebugReturnConfig(TInt aReplyBufSize, MWsElement* aElement, TInt /*aFlags*/) const
	{
	if (aElement == NULL)
		{
		return KErrNotReady;
		}

	TSurfaceConfiguration config(aReplyBufSize);
	TInt retVal=config.Size();
	if (aReplyBufSize)
		{
		retVal = CWindowElementSet::GetConfiguration(config, *aElement);
		if (retVal==KErrNone)
			{
			ReplyBuf(&config, config.Size()); //return code is 0 = "just right"
			}
		}
	return retVal;
	}

/**	Returns the base region of the element.
 * 	This region is element relative. There are a number of ways that this does not match the input region:
 * 	First, if no region is specified then the extent rectangle is returned
 * 	Any region returned has all negative ordinate values clipped. 
 * 	Positive values may exceed the extent, but negative values are never returned. 
 *  Internally, a region which is only negative is "remembered illegally", but an empty region is returned.
 **/
TInt CWsClient::DebugReturnBase(TInt /*aReplyBufSize*/, const MWsElement* /*aElement*/)const
	{
	return KErrNotSupported;
	}

/**	Returns the flags associated with the given element.
 * 	2 words are inserted.
 * 	One represents the MWsElement flags, the other represents CWindowElement or UIElement flags
 * 	@return length of two words
 **/
TInt CWsClient::DebugReturnFlags(TInt aReplyBufSize, const MWsElement* /*aElement*/, TInt aFlags)const
	{
	const TInt KArraySize=2;
	if (aReplyBufSize>KArraySize*sizeof(TInt))
		{
		// First field is for flags from scene element if any
		TInt returns[KArraySize]=
			{
			0, aFlags
			};
		ReplyBuf(returns,KArraySize*sizeof(TInt));
		}
	return KArraySize*sizeof(TInt);
	}

/**	Packages a region for return ans an array of rectangles.
 * 	If the buffer is big enough the data is transferred
 * 	@return the buffer size required, or an error code if an empty or null pointer is passed in
 **/
TInt CWsClient::DebugReturnRegion(TInt aReplyBufSize, const TRegion* aRegion, TInt aErrCodeIfEmpty)const
	{
	if (aRegion==NULL)
		return KErrNotReady;
	
	const TInt returnSize=aRegion->Count()*sizeof(TRect);
	if (returnSize==0)
		return aErrCodeIfEmpty;
	
	if (returnSize<=aReplyBufSize)
		ReplyBuf(aRegion->RectangleList(),returnSize);
	
	return returnSize;
	}

void CWsClient::ReplyGroupName(HBufC* aName, TInt aMaxLength)	// static
	{
	if (aName)
		{
		if (aName->Length()>aMaxLength)
			{
			ReplyBuf(aName->Left(aMaxLength));
			SetReply(KErrOverflow);
			}
		else
			ReplyBuf(*aName);
		}
	else
		ReplyBuf(KNullDesC);
	}

void CWsClient::TriggerRedraw()
	{
	RedrawQueue()->TriggerRedraw();
	}

void CWsClient::UpdateWindowOrdinalPrioritys()
	{
	for(CWsWindowGroup* win=iScreen->RootWindow()->Child();win;win=win->NextSibling())
		{
		if (win->WsOwner()==this)
			win->UpdateOrdinalPriority(ETrue);
		}
	}

void CWsClient::DeleteSystemPointerListEntry(TInt aIndex)
	{
	PointerCursor (aIndex)->Close();
	iSystemPointerCursors->Delete(aIndex);
	}

CWsPointerCursor* CWsClient::SystemPointerCursor(TInt aIndex)
	{
	TInt arrayIndex;
	if (iSystemPointerCursors)
		{
		if (FindCursorArrayItem(iSystemPointerCursors, aIndex, arrayIndex))
			return PointerCursor(arrayIndex);

		// Cursor not defined so try for default cursor
		if (FindCursorArrayItem(iSystemPointerCursors, 0, arrayIndex))
			return PointerCursor(arrayIndex);
		}

	// If that fails simply return NULL for no cursor
	return NULL;
	}

void CWsClient::SetSystemPointerCursorL(TInt aIndex, CWsPointerCursor* aCursor)
	{
	if (iSystemPointerCursorListOwner!=this)
		PPanic(EWservPanicNotSystemPointerCursorListOwner);
	
	TInt arrayIndex = KErrNotFound;
	if (FindCursorArrayItem(iSystemPointerCursors, aIndex, arrayIndex))
		{
		PointerCursor(arrayIndex)->Close();
		PointerCursor(arrayIndex) = aCursor;
		}
	else
		{
		TWsCursorArrayItem entry;
		entry.iIndex=aIndex;
		entry.iCursor=aCursor;
		iSystemPointerCursors->InsertIsqL(entry, iCursorKey);
		}
	
	aCursor->Open();
	if (aIndex==iDefaultSystemPointerCursorIndex)
		iDefaultSystemPointerCursor=aCursor;
	TWsPointer::UpdatePointerCursor();
	}

void CWsClient::ClearSystemPointerCursor(TInt aIndex)
	{
	if (iSystemPointerCursorListOwner!=this)
		PPanic(EWservPanicNotSystemPointerCursorListOwner);
	
	TInt arrayIndex;
	if (FindCursorArrayItem(iSystemPointerCursors, aIndex, arrayIndex))
		{
		DeleteSystemPointerListEntry(arrayIndex);
		if (aIndex==iDefaultSystemPointerCursorIndex)
			iDefaultSystemPointerCursor=NULL;
		}
	}

void CWsClient::ClaimSystemPointerCursorListL()
	{
	if (iSystemPointerCursorListOwner)
		User::Leave(KErrInUse);
	
	const TInt systemPointerCursorGranularity = 4;
	iSystemPointerCursors = new(ELeave) CArrayFixFlat<TWsCursorArrayItem> (systemPointerCursorGranularity);
	iSystemPointerCursorListOwner=this;
	}

void CWsClient::FreeSystemPointerCursorList()
	{
	if(iSystemPointerCursorListOwner == this)
		{
		iSystemPointerCursorListOwner = NULL;
		
		while(iSystemPointerCursors->Count()>0)
			DeleteSystemPointerListEntry(0);
		
		iDefaultSystemPointerCursor = NULL;
		iDefaultSystemPointerCursorIndex = 0;
		
		delete iSystemPointerCursors;
		iSystemPointerCursors = NULL;
		}
	}

void CWsClient::SetDefaultSystemPointerCursor(TInt aIndex)
	{
	TInt arrayIndex;
	if (iSystemPointerCursorListOwner != this)
		PPanic(EWservPanicNotSystemPointerCursorListOwner);
	
	iDefaultSystemPointerCursorIndex = aIndex;
	iDefaultSystemPointerCursor = NULL;
	
	if (aIndex != ENoDefaultSystemPointerCursor &&
		FindCursorArrayItem(iSystemPointerCursors, aIndex, arrayIndex))
		iDefaultSystemPointerCursor = PointerCursor (arrayIndex);
	else
		iDefaultSystemPointerCursor = NULL;
	
	TWsPointer::UpdatePointerCursor();
	}

TBool CWsClient::FindCursorArrayItem(CArrayFixFlat<TWsCursorArrayItem>* aCursorArray,
									 TInt aIndex,TInt& aPosition)
	{
	if (!aCursorArray)
		return EFalse; // No hit if the array isn't even allocated

	TWsCursorArrayItem entry;
	entry.iIndex = aIndex;
	return aCursorArray->FindIsq(entry, iCursorKey, aPosition)==KErrNone;
	}

void CWsClient::SetClientPriority()
	{
	if (iComputeMode!=RWsSession::EPriorityControlDisabled)
		{
		Client().SetProcessPriority(
				iComputeMode==RWsSession::EPriorityControlComputeOn 
			||	CWsTop::FocusWindowGroupOwner()!=this
				?	EPriorityBackground
			  	:	EPriorityForeground);
		}
	}

void CWsClient::SetComputeMode(RWsSession::TComputeMode aComputeMode)
	{
	if (aComputeMode!=RWsSession::EPriorityControlDisabled 
		&& aComputeMode	!=RWsSession::EPriorityControlComputeOn 
		&& aComputeMode	!=RWsSession::EPriorityControlComputeOff)
		PPanic(EWservPanicSetComputeMode);
	iComputeMode=aComputeMode;
	SetClientPriority();
	}

void CWsClient::CompleteMessage(const RMessage2& aMessage,TInt aReason)
	{
	WS_ASSERT_DEBUG(!aMessage.IsNull(),EWsPanicCompleteNullMessage);
	// This defensive check should not be necessary as aMessage should never
	// be null, but in rare situations it is and WServ would die without this check.
	if (!aMessage.IsNull())
		{
		if (iInternalFlags&EPanicClientAsSoonAsPossible)
			{
			aMessage.Panic(KWSERVSessionPanicCategory,iPanicReason);
			iInternalFlags&=~EPanicClientAsSoonAsPossible;
			}
		else
			{
			if(!iResponseHandle)
				aMessage.Complete(aReason);
			else
				{
				aMessage.Complete(*iResponseHandle);
				iResponseHandle=NULL;
				}
			}
		}
    }

void CWsClient::ServiceError(const RMessage2& /*aMessage*/,TInt aError)
	{
	CompleteMessage(iClientMessage,aError);	// (finish)
	}

void CWsClient::ServiceL(const RMessage2 &aMessage)	// (step ##1)
//
// Handle messages for the window server server.
//
	{
	iClientMessage=aMessage; // from now on use always the message stored in the session
	if (iInternalFlags&EPanicClientAsSoonAsPossible)
		{
		iClientMessage.Panic(KWSERVSessionPanicCategory,iPanicReason);
		}
	else
		{
		iPanicReason=KErrNone;
		iReply=KErrNone;
		TBool completeRequest=ETrue;
		DoServiceL(iClientMessage, completeRequest);	// (call #2)
		if (completeRequest)
			CompleteMessage(iClientMessage,iReply);	// (finish)
		}
	}

void CWsClient::SetResponseHandle(RHandleBase* aHandle)
	{
	iResponseHandle = aHandle;
	}

void CWsClient::DoServiceL(const RMessage2& aMessage, TBool& aCompleteRequest)	// (step #2)
	{
	if (aMessage.IsNull())
		PPanic(EWservPanicNullMessageFromClient);
	
	WS_ASSERT_DEBUG(iInternalFlags&EFinishedProcessingCommands,EWsPanicCommandBufferStillBeingProcessed);

	const TInt function = aMessage.Function();
	switch (function)
		{
	case EWservMessInit:
		StartInitializationL(iConnectionId++);
		break;
	case EWservMessSyncMsgBuf:
	case EWservMessCommandBuffer:	// Process command buffer containing draw ops
		{
		if (!IsInitialised())			
			PPanic(EWservPanicUninitialisedClient);
			
		const TInt err = aMessage.Read(KBufferMessageSlot, iCmdBuf);
		if (!err)
			{
			iReplyOffset=0;
			iDestObj=NULL;
			iNextCmd=iCmdBuf.Ptr();
			DoServiceCommandBuf();	// (call #3.1)
			}
		else if (err!=KErrDied)
			PPanic(EWservPanicDescriptor);
		
		if(function == EWservMessCommandBuffer && CWsTop::FinishEveryFlush())
			Screen()->DoRedrawNow();
		else
			aCompleteRequest=EFalse;
		}
		break;
	case EWservMessShutdown:
		{
		if(!KSecurityPolicy_PowerMgmt().CheckPolicy(ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for EWservMessShutdown message ")))
			PPanic(EWservPanicPermissionDenied);

		if (aMessage.Int0() == EWservShutdownCheck)
			CWsTop::Exit();
		else
			PPanic(EWservPanicHandle);
		}
		break;
	case EWservMessFinish:
		Screen()->DoRedrawNow();
		break;
	default:
		if (function&EWservMessAsynchronousService)
			{
			TRAPD(err, ExecuteAsyncClientCommandL((function&~EWservMessAsynchronousService), aMessage));	// (call #3.2)
			aCompleteRequest = (err!=KErrNone);
			WS_ASSERT_DEBUG((!(iInternalFlags&EPanicClientAsSoonAsPossible))==(!aCompleteRequest), EWsPanicPanicFlagError);
			}
		else if (function&EWservMessAnimDllAsyncCommand)
			{
			CWsAnimDll* const animDll = static_cast<CWsAnimDll*>(HandleToObj(aMessage.Int0(), WS_HANDLE_ANIM_DLL));
			if (!animDll)
				{
				SessionPanic(EWservPanicHandle);
				break;
				}
				
			// it looks wrong to call CommandReply here (not AsyncCommandReply, or something, which doesn't exist), but basically, we can't add a virtual AsyncCommandReplyL to CAnim to correspond to RAnim::AsyncCommandReply as that would break binary and source compatibility for Anim plug-ins; instead asynchronous commands are done by the plug-in having to complete the RMessagePtr2 returned by iFunctions->Message() (or a copy of of that object) for asynchronous commands only
			TRAPD(err, animDll->AnimObjectL(aMessage.Int1())->CommandReply(function&~EWservMessAnimDllAsyncCommand,NULL));
			aCompleteRequest=(err!=KErrNone);
			WS_ASSERT_DEBUG((!(iInternalFlags&EPanicClientAsSoonAsPossible))==(!aCompleteRequest), EWsPanicPanicFlagError);
			}
		else
			SetReply(KErrNotSupported);
		}
	}
void CWsClient::RemoteRead(TDes16& aDes, TInt aOffset)
	{
	if (iClientMessage.Read(KRemoteBufferMessageSlot,aDes,aOffset)!=KErrNone)
		SessionPanic(EWservPanicDescriptor);
	}

void CWsClient::RemoteRead(TDes8& aDes, TInt aOffset)
	{
	if (iClientMessage.Read(KRemoteBufferMessageSlot,aDes,aOffset)!=KErrNone)
		SessionPanic(EWservPanicDescriptor);
	}

void CWsClient::RemoteReadL(TDes16& aDes, TInt aOffset)
	{
	iClientMessage.ReadL(KRemoteBufferMessageSlot,aDes,aOffset);
	}

void CWsClient::RemoteReadL(TDes8& aDes, TInt aOffset)
	{
	iClientMessage.ReadL(KRemoteBufferMessageSlot,aDes,aOffset);
	}

void CWsClient::InitStaticsL()
	{
	}

void CWsClient::DeleteStatics()
	{
	if (iTextCursorArray)
		{
		const TInt count = iTextCursorArray->Count();
		for (TInt index=0;index<count;index++)
			delete iTextCursorArray->At(index).iCursor;

		delete iTextCursorArray;
		iTextCursorArray = NULL;
		}

	// coverity[extend_simple_error] 
	}
		
/* CWsClient implementing MWsClient */

TBool CWsClient::HasCapability(TCapability aCapability) const
	{
	return iClient.HasCapability(aCapability);
	}

TSecureId CWsClient::SecureId() const
	{
	return iClient.SecureId();
	}

TVendorId CWsClient::VendorId() const
	{
	return iClient.VendorId();
	}

/**
Makes a new copy of the aData. so it could be deleted after this call.
*/
TInt CWsClient::SendMessage(const CWsGraphicDrawer* aOnBehalfOf,const TDesC8& aData)
	{
	CWsGraphicMessageQueue::CMessage* msg = CWsGraphicMessageQueue::CMessage::New(aData);
	if(msg)
		return SendMessage(aOnBehalfOf, *msg);
	
	return KErrGeneral;
	}

/** adds a message to the message queue
@return a postive number to uniquely identify the message
*/
TInt CWsClient::SendMessage(const CWsGraphicDrawer* aOnBehalfOf,CWsMessageData& aData)
	{
	WS_ASSERT_DEBUG(aData.Data().Size(), EWsPanicWsGraphic);
	const CWsGraphicDrawerObject* obj = DrawerObject(aOnBehalfOf);
	WS_ASSERT_DEBUG(obj, EWsPanicWsGraphic);
	if(obj)
		{
		// assign message id
		if(iMessageIdSeq == KMaxTInt) // Wrap if iMessageIdSeq has reached KMaxTInt
			iMessageIdSeq = 0;
		
		iMessageIdSeq++;
		// correct other handles
		aData.iClientHandle = (obj->ClientHandle() | (EWsGraphMessageTypeUser & 0x03));
		aData.iDrawer = obj->Drawer();
		aData.iId = iMessageIdSeq;
		iGraphicMessageQueue.Queue(&aData);
		return iMessageIdSeq;
		}

	return KErrGeneral;
	}


CWsGraphicDrawerObject* CWsClient::DrawerObject(const CWsGraphicDrawer* aDrawer)
	{
	const TInt count = ObjectIndex()->Length();
	for(TInt i=0; i<count; i++)
		{
		CWsObject* obj = const_cast<CWsObject*>(ObjectIndex()->At(i));
		if(obj && (WS_HANDLE_GRAPHIC_DRAWER == obj->Type()))
			{
			CWsGraphicDrawerObject* candidate = static_cast<CWsGraphicDrawerObject*>(obj);
			if(candidate->Drawer() == aDrawer)
				return candidate;
			}
		}

	return NULL;
	}

const CWsGraphicDrawerObject* CWsClient::DrawerObject(const CWsGraphicDrawer* aDrawer) const
	{
	CWsObjectIx* objectIndex = const_cast<CWsClient*>(this)->ObjectIndex();
	const TInt count = objectIndex->Length();
	for(TInt i=0; i<count; i++)
		{
		CWsObject* obj = const_cast<CWsObject*>(objectIndex->At(i));
		if(obj && (WS_HANDLE_GRAPHIC_DRAWER == obj->Type()))
			{
			const CWsGraphicDrawerObject* candidate = static_cast<CWsGraphicDrawerObject*>(obj);
			if(candidate->Drawer() == aDrawer)
				return candidate;
			}
		}

	return NULL;
	}

TInt CWsClient::RegisterSurface(const TWsClCmdUnion& pData)
	{
	TInt screenNumber = pData.SurfaceRegister->screenNumber;
	if (screenNumber<0 || screenNumber>=CWsTop::NumberOfScreens())
		{
		PPanic(EWservPanicScreenNumber);
		}
	if (pData.SurfaceRegister->surfaceId.Type() == TSurfaceId::EScreenSurface
			|| pData.SurfaceRegister->surfaceId.IsNull())
		{
		PPanic(EWservPanicInvalidSurface);
		}

	CRegisteredSurfaceMap* surfaceMap = CWsTop::Screen(screenNumber)->SurfaceMap();
	const TSurfaceId& surfaceId = pData.SurfaceRegister->surfaceId;
	TInt err = surfaceMap->Add(*this,surfaceId);

	switch(err)
		{
	case KErrNone:
	case KErrNoMemory:
	case KErrInUse:
	case KErrArgument:
		break;
	default:
		PPanic(EWservPanicInvalidSurface);
		}
	return err;
	}

void CWsClient::UnregisterSurface(const TWsClCmdUnion& pData)
	{
	TInt screenNumber = pData.SurfaceRegister->screenNumber;
	if (screenNumber<0 || screenNumber>=CWsTop::NumberOfScreens())
		{
		PPanic(EWservPanicScreenNumber);
		}
	TInt err = CWsTop::Screen(screenNumber)->SurfaceMap()->Remove(*this,pData.SurfaceRegister->surfaceId);
	WS_ASSERT_DEBUG((err==KErrNone||err==KErrNotFound), EWsPanicSurfaceMapError);
	}

void CWsClient::CreateDrawableSourceL(const TWsClCmdCreateDrawableSource& aDrawableSourceData)
	{
	CWsDrawableSource* drawableSource = new(ELeave) CWsDrawableSource(this);
	CleanupStack::PushL(drawableSource);
	drawableSource->ConstructL(aDrawableSourceData);
	CleanupStack::Pop();
	}

//
// class CWsCliObj
//

CWsCliObj* CWsCliObj::NewL(CWsClient* aOwner)
	{
	CWsCliObj* self = new(ELeave) CWsCliObj(aOwner);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CWsCliObj::CWsCliObj(CWsClient *aOwner) :
	CWsObject(aOwner, WS_HANDLE_CLIENT)
	{
	}
	
void CWsCliObj::ConstructL()
	{
	NewObjL();	
	}

void CWsCliObj::CommandL(TInt aOpcode, const TAny* aCmdData)	// (step #5)
	{
	iWsOwner->ExecuteCommandL(aOpcode,aCmdData);	// (call #6)
	}

CWsObject* CWsClient::HandleToObjUntyped(TInt aHandle)
	{
	return iObjectIndex->HandleToObject(aHandle);
	}

const CWsObject* CWsClient::HandleToObjUntyped(TInt aHandle) const
	{
	return const_cast<CWsClient*>(this)->HandleToObjUntyped(aHandle);
	}

CWsObject* CWsClient::HandleToObj(TInt aHandle, WH_HANDLES aType)
	{
	CWsObject* object = HandleToObjUntyped(aHandle);
	return (object && object->Type() == aType) ? object : NULL;
	}


const CWsObject* CWsClient::HandleToObj(TInt aHandle, WH_HANDLES aType) const
	{
	return const_cast<CWsClient*>(this)->HandleToObj(aHandle, aType);
	}

void CWsClient::SetRetryFlag(TEventCode aEventCode)
	{
	switch(aEventCode)
		{
		//To be expanded
		case EEventDisplayChanged:
			{
			iInternalFlags |= ERetryDisplayEvent;
			}
		break;
		
		}
	}
TBool CWsClient::RetryEvent(TEventCode aEventCode)
	{
	switch(aEventCode)
		{//To be expanded
		case EEventDisplayChanged:
			{
			return (iInternalFlags & ERetryDisplayEvent);
			}
		}
	return EFalse;
	}

void CWsClient::RemoveRetryFlag(TEventCode aEventCode)
	{
	switch(aEventCode)
		{//To be expanded
		case EEventDisplayChanged:
			{
			iInternalFlags &= ~ERetryDisplayEvent;
			}
		break;
		}
	}

