// Copyright (c) 1995-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 window functions
// 
//

#include "W32CLICK.H"
#include <graphics/wselement.h>
#include "server.h"
#include "cliwin.h"
#include "gc.h"
#include "rootwin.h"
#include "windowgroup.h"
#include "walkwindowtree.h"
#include "ScrDev.H"
#include "wstop.h"
#include "EVQUEUE.H"
#include "KEYCLICK.H"
#include "panics.h"
#include "password.h"
#include "pointer.h"
#include "EVENT.H"
#include "backedupwindow.h"
#include "redrawmsgwindow.h"
#include "windowelementset.h"




TBool CWsClientWindow::iAbsoluteFading = EFalse;

const TPoint corner1[1]={TPoint(1,1)};
const TPoint corner2[2]={TPoint(2,1),TPoint(1,1)};
const TPoint corner3[2]={TPoint(3,1),TPoint(1,2)};
const TPoint corner5[4]={TPoint(5,1),TPoint(3,1),TPoint(2,1),TPoint(1,2)};

/*CWsClientWindow*/

CWsClientWindow::CWsClientWindow(CWsClient* aOwner, CScreen* aScreen) : CWsWindow(aOwner,WS_HANDLE_WINDOW,aScreen)
	{
	iWinType=EWinTypeClient;
	}

void CWsClientWindow::ConstructL(const TWsClCmdCreateWindow &aCmd, CWsWindowBase *aParent, TBool aScreenDeviceIsInvalid)
	{
	CWsWindow::Construct();
	NewObjL();
	if (aCmd.clientHandle==NULL)
		OwnerPanic(EWservPanicNullHandle);
#if defined(_DEBUG)
	if (IsClientHandleInUse(aCmd.clientHandle))
		OwnerPanic(EWservPanicDuplicateHandle);
#endif
	iPointerFilter=EPointerFilterEnterExit|EPointerFilterMove|EPointerFilterDrag;
	iClientHandle=aCmd.clientHandle;
	CWsWindow* inherit=static_cast<CWsWindow *>(aParent);
	if (aParent->WinType()==EWinTypeGroup)
		inherit=RootWindow();
	SetPointerCursor(aParent->PointerCursor());
	iAbs=inherit->Abs();
	iOrigin=aParent->Origin();
	iRel.iBr.iX=inherit->Rel().iBr.iX-inherit->Rel().iTl.iX;
	iRel.iBr.iY=inherit->Rel().iBr.iY-inherit->Rel().iTl.iY;
	switch(aCmd.type)
		{
		case EWinRedraw:
			iRedraw=new(ELeave) CWsRedrawMsgWindow(this);
			break;
		case EWinBackedUp:
			iRedraw=new(ELeave) CWsBackedUpWindow(this, aCmd.displayMode);
			iAbs.iBr=iAbs.iTl;
			iRel.iBr=iRel.iTl;
			break;
		case EWinBlank:
			iRedraw=new(ELeave) CWsBlankWindow(this);
			break;
		default:
			OwnerPanic(EWservPanicRedrawType);
		}
	ResetHiddenFlag();
	SetCornerTypeL(EWindowCornerSquare,0,NULL,EFalse);
	CWsWindowBase::ConstructL(aParent);
	if (aScreenDeviceIsInvalid)
		{
		iFlags|=EFlagScreenDeviceInvalid;
		ResetHiddenFlag();
		}
	iRedraw->ConstructL();
	}

void CWsClientWindow::GetBaseAreaOfNode(RWsRegion &aRegion) const
    {
    if (iBaseArea)
        {
        aRegion.Copy(*iBaseArea);
        }
    aRegion.ClipRect(iAbs);
    }

void CWsClientWindow::ClipRegionToBaseArea(RWsRegion &aRegion) const
    {
    if (iBaseArea)
        {
        aRegion.Intersect(*iBaseArea);
        }
    aRegion.ClipRect(iAbs);
    }

void CWsClientWindow::GetClippedBaseArea(RWsRegion &aRegion) const
	{
	const CWsWindowBase* ancestor = BaseParent();	    
	GetBaseAreaOfNode(aRegion);	
	while (ancestor && ancestor->WinType() == EWinTypeClient)
	    {
	    static_cast<const CWsClientWindow*>(ancestor)->ClipRegionToBaseArea(aRegion);       
	    ancestor = ancestor->BaseParent();
	    }
	}

void CWsClientWindow::GetOpaqueBaseAreaOfNode(RWsRegion &aRegion) const
    {
    if (IsTranslucent())
        {
        if (iUserDefinedOpaqueRegion)
            {
            aRegion.Copy(*iUserDefinedOpaqueRegion);
            aRegion.ClipRect(iAbs);
            }
        else
            {
            aRegion.Clear();
            }
        }
    else
        {
        GetBaseAreaOfNode(aRegion);
        }
    }

void CWsClientWindow::ClipRegionToOpaqueBaseArea(RWsRegion& aRegion) const
    {
    if (IsTranslucent())
        {
        if (iUserDefinedOpaqueRegion)
            {
            aRegion.Intersect(*iUserDefinedOpaqueRegion);
            aRegion.ClipRect(iAbs);
            }
        else
            {
            aRegion.Clear();
            }
        }
    else
        {
        ClipRegionToBaseArea(aRegion);
        }
    }

void CWsClientWindow::GetOpaqueClippedBaseArea(RWsRegion &aRegion) const
	{
	const CWsWindowBase* ancestor = BaseParent();
	GetOpaqueBaseAreaOfNode(aRegion);
	while (ancestor && ancestor->WinType() == EWinTypeClient)
	    {
	    static_cast<const CWsClientWindow*>(ancestor)->ClipRegionToOpaqueBaseArea(aRegion);
	    ancestor = ancestor->BaseParent();
	    }
	}

TInt CWsClientWindow::GetNonOpaqueBaseAreaOfNode(RWsRegion &aRegion) const
    {
    aRegion.Clear();
    if (IsTranslucent())
        {
        if(iUserDefinedTransparentRegion)
            {
            aRegion.Copy(*iUserDefinedTransparentRegion);
            aRegion.ClipRect(iAbs);
            return KErrNone;
            }
        }  
    return KErrNotFound;
    }

void CWsClientWindow::ResetHiddenFlag()
//
// Reset the status of the hidden flag based on the current states of the active and invisible flags
//
	{
	CWsClientWindow *parent=static_cast<CWsClientWindow*>(iParent);

	TBool wasHidden = iFlags&EFlagHidden;
	TBool nowHidden = (parent==NULL || 
		              (parent->WinType()==EWinTypeClient && !parent->IsVisible()) ||
	                  !(iFlags&EFlagActive) ||
	                  (iFlags&EFlagInvisible) ||
			          (iFlags&EFlagScreenDeviceInvalid));

	if (nowHidden)
		{
		iFlags|=EFlagHidden;
		iFlags&=~EFlagDrawnToScreen;
		}
	else
		{
		iFlags&=~EFlagHidden;
		}
	if ((!nowHidden) != (!wasHidden))
		{
		// intentionally call the screen directly
		iScreen->ScheduleRegionUpdate(&iVisibleRegion);
		
		WS_ASSERT_DEBUG(!iDirtyWindowRegion.CheckError(),EWsPanicErrorInRegion);
		WS_ASSERT_DEBUG(!iDirtySpriteRegion.CheckError(),EWsPanicErrorInRegion);
	//	WS_ASSERT_DEBUG(!InvalidArea().CheckError(),EWsPanicErrorInRegion);		//error flag in invalid area may be set in OOM cases
																				//thus the assert statement is caused to fail
		if (wasHidden && iScreen->ChangeTracking() && 
				(!iDirtyWindowRegion.IsEmpty() || !iDirtySpriteRegion.IsEmpty() || !InvalidArea().IsEmpty()))
			{
			// Window has just become visible, schedule it
			iScreen->ScheduleWindow(this);
			}
		}
	}
	
void CWsClientWindow::ResetHiddenFlags()
	{
	CWsClientWindow *win=this;
	FOREVER
		{
		TUint oldHiddenFlag=win->iFlags&EFlagHidden;
		win->ResetHiddenFlag();
		if ((win->iFlags&EFlagHidden)!=oldHiddenFlag)	// If hidden status hasn't changed nothing to do
			{
			win->SetElementOpacity(IsVisible() ? 0xFF : 0x00);	// Update element visibility
			if (win->Child())
				{
				win=win->Child();
				continue;
				}
			}
		if (win==this)
			return;
		while(!win->NextSibling())
			{
			win=(CWsClientWindow *)win->BaseParent();
			if (win==this)
				return;
			}
		win=win->NextSibling();
		} // for loop ends
	}

void CWsClientWindow::OffsetBaseArea(const TPoint &aOffset)
	{
	iBaseArea->Offset(aOffset);
	//If the given window's position changes, then update.
	if (aOffset.iX || aOffset.iY)
		{
		UpdateElementExtent(&aOffset);
		}
	}

void CWsClientWindow::CalcBaseArea()
//
// The windows basic area before any clipping is done
//
	{
	TInt cornerType=iCornerData&ECornerTypeMask;
	if (cornerType==EWindowCornerRegion)
		iBaseArea->ClipRect(FullRect());
	else
		{
		TSize size=Size();
		iBaseArea->Clear();
		const TPoint *corners=NULL;
		TInt count=0;
		switch(cornerType)
			{
			case EWindowCorner1:
				count=sizeof(corner1)/sizeof(TPoint);
				corners=corner1;
				break;
			case EWindowCorner2:
				count=sizeof(corner2)/sizeof(TPoint);
				corners=corner2;
				break;
			case EWindowCorner3:
				count=sizeof(corner3)/sizeof(TPoint);
				corners=corner3;
				break;
			case EWindowCorner5:
				count=sizeof(corner5)/sizeof(TPoint);
				corners=corner5;
				break;
			default:
				break;
			}
		TInt top=0;
		TInt bot=size.iHeight;
		for(TInt index=0;index<count;index++)
			{
			TInt xadjust=corners[index].iX;
			TInt yadjust=corners[index].iY;
			if ((iCornerData&(EWindowCornerNotTL|EWindowCornerNotTR))!=(EWindowCornerNotTL|EWindowCornerNotTR))
				{
				iBaseArea->AddRect(TRect(iCornerData&EWindowCornerNotTL?0:xadjust,top,
										 size.iWidth-(iCornerData&EWindowCornerNotTR?0:xadjust),top+yadjust));
				top+=yadjust;
				}
			if ((iCornerData&(EWindowCornerNotBL|EWindowCornerNotBR))!=(EWindowCornerNotBL|EWindowCornerNotBR))
				{
				iBaseArea->AddRect(TRect(iCornerData&EWindowCornerNotBL?0:xadjust,bot-yadjust,
										 size.iWidth-(iCornerData&EWindowCornerNotBR?0:xadjust),bot));
				bot-=yadjust;
				}
			}
		iBaseArea->AddRect(TRect(0,top,size.iWidth,bot));
		iBaseArea->Offset(Origin());
		iBaseArea->ClipRect(FullRect());
		iBaseArea->Sort();
		}
	}

void CWsClientWindow::GenerateArea(RWsRegion &aArea, TBool aClipTranslucent) const
//
// Create the window area list.
//
	{
	aArea.Clear();
	if (IsVisible())
		{
		aArea.Copy(*iBaseArea);
		aArea.ClipRect(iAbs);
		const CWsClientWindow *win=this;
		FOREVER
			{
			if (win->IsTopClientWindow())
				break;
			ClipWindows(aArea,(CWsClientWindow *)win->BaseParent()->BaseChild(),win,aClipTranslucent);
			win=(CWsClientWindow *)win->iParent;
			}
		TInt tidyCount=0;
		for(const CWsTopClientWindow *cwin=RootWindow()->FirstTopClientWindow();aArea.Count() && cwin!=win;cwin=cwin->NextSiblingMultiParent())
			{
			if (!tidyCount--)
				{
				aArea.Tidy();
				tidyCount=ETidyCountSetting;	// Tidy every ETidyCountSetting times around
				}
			if (cwin->IsVisible())
				{
				if (cwin->IsTranslucent() && !aClipTranslucent)
					{
					if (cwin->iUserDefinedOpaqueRegion)
						{
						aArea.SubRegion(*cwin->iUserDefinedOpaqueRegion);
						}
					}
				else
					{
					aArea.SubRegion(*cwin->iBaseArea);
					}
				}
			}
		aArea.Tidy();
		}
	}

void CWsClientWindow::ClipWindows(TRegion &region,const CWsClientWindow *start, const CWsClientWindow *end, TBool aClipTranslucent)
//
// Remove out of the region the opaque part of the abs rect of all the windows starting from 'start'
// along the sibling list to (and not including) the end window.
//
	{
	for(const CWsClientWindow *win=start;region.Count() && win!=end;win=win->NextSibling())
		{
		if (win->IsVisible())
			{
			if (win->IsTranslucent() && !aClipTranslucent)
				{
				if (win->iUserDefinedOpaqueRegion)
					{
					region.SubRegion(*win->iUserDefinedOpaqueRegion);
					}
				}
			else
				{
				region.SubRegion(*win->iBaseArea);
				}
			}
		}
	}

void CWsClientWindow::GenerateTopRegion(RWsRegion& aRegion) const
	{
	GenerateArea(aRegion,ETrue);
	if (iChild)
		ClipWindows(aRegion,Child(),NULL,ETrue);
	}

void CWsClientWindow::GenerateWindowRegion(RWsRegion &aRegion) const
//
// Calculate the windows clipping region without using the usual stored iArea or iRegion fields
// this function is used by the screen backup code to calculate "what if" regions to work out
// whether something would be visible if the backed up window didn't exist, on this basis we
// don't want to modify the existing copies of iArea & iRegion.
//
	{
	GenerateArea(aRegion,EFalse);
	if (iChild)
		ClipWindows(aRegion,Child(),NULL,EFalse);
	}

const TRegion *CWsClientWindow::DrawingRegion()
	{
	return (&iRedraw->BaseDrawRegion());
	}

void CWsClientWindow::RecalcChildAbs(const TPoint *aOffset)
	{
	CWsClientWindow *win=this;
	FOREVER
		{
		FOREVER
			{
			win->SetAbsFromRel();
			if (aOffset)
				win->OffsetBaseArea(*aOffset);
			if (win->Child()==NULL)
				break;
			win=win->Child();
			}
		FOREVER
			{
			if (win==this)
				return;
			if (win->NextSibling()!=NULL)
				{
				win=win->NextSibling();
				break;
				}
			win=(CWsClientWindow *)win->iParent;	// The cast is safe as the loop is aborted when win==this
			}
		}
	}

void CWsClientWindow::SetAbsFromRel()
	{
	iOrigin=iRel.iTl+iParent->Origin();
	iAbs=iRel;
	iAbs.Move(iParent->Origin());
	iAbs.Intersection(iParent->AbsRect());
	}

void CWsClientWindow::SetExtentL(const TPoint *aPos,const TSize *aSize)
	{
	if (iParent==NULL)
		OwnerPanic(EWservPanicParentDeleted);
	TPoint offset = TPoint(0,0);
	TSize oldSize;
	TSize newSize;
	TBool sizeChanged = EFalse;
	TBool posChanged = EFalse;
	
	if (aPos)
		{
		offset = *aPos+iParent->Origin()-iOrigin;
		if (offset.iX != 0 || offset.iY != 0)
			{
			posChanged = ETrue;
			}
		}
		
	if (posChanged)
		{
		TWalkWindowTreeScheduleRedraws wwt;
		WalkWindowTree(wwt, EWalkChildren);
		}
	
	if (aSize)
		{
		newSize=*aSize;
		if (newSize.iWidth<0)
			newSize.iWidth=0;
		if (newSize.iHeight<0)
			newSize.iHeight=0;
		// This should be the only part of resizing that can fail
		// and it can only fail for backedup windows.
		iRedraw->PrepareForResizeL(newSize,oldSize);
		sizeChanged = *aSize != iRel.Size();
		}

	if (posChanged)
		{
		iRel.Move(offset);
		RecalcChildAbs(&offset);      // Also calls UpdateElementExtent(offset)
		TWalkWindowTreeOffsetTransparentRegions offsetTransparent(offset);
		WalkWindowTree(offsetTransparent, EWalkChildren);
		}

	if (sizeChanged)
		{
		iRel.SetSize(newSize);
		RecalcChildAbs(NULL);
		CalcBaseArea();
		iRedraw->Resize(newSize,oldSize);
		if (Redraw()->HasElement())
		    UpdateElementExtent();
		}
	
	if ((posChanged || sizeChanged) && Redraw()->HasElement())
		{
		TRect interSection(iParent->Origin(), iParent->Size());
		interSection.Intersection(FullRect());
		if (interSection == FullRect())
			{
			// There is no any clipping in this case
			interSection = TRect();
			}
		// Get the corresponding source rectangle for the element
		if (!iOriginalSrcElementRect.IsEmpty() && !iOriginalDestElementRect.IsEmpty() && !iAbs.IsEmpty())
			{
			MWsElement* element = Screen()->WindowElements().GetElementFromWindow(*this);
			if (element)
				{
				element->SetDestinationClippingRect(interSection);
				}
			}
		}	
	
	if (posChanged || sizeChanged)
		{
		iRedraw->ClipInvalidRegion(TRect(iRel.Size()));
		iRedraw->Moved();
		ScheduleRegionUpdate(NULL);
		TWalkWindowTreeRecalcOpaque recalcOpaque;
		WalkWindowTree(recalcOpaque, EWalkChildren);

		MWsWindowTreeObserver* windowTreeObserver = Screen()->WindowTreeObserver();
		if (windowTreeObserver)
			{
			windowTreeObserver->NodeExtentChanged(*this, FullRect());
			}
		}
	}


void CWsClientWindow::GetElementFlipAndRotation(TBool& aElemetFlip, MWsElement::TElementRotation& aElemenetRotation)
    {
    MWsElement* element = Screen()->WindowElements().GetElementFromWindow(*this);
    if (element)
        {
        aElemetFlip = element->SourceFlipping();
        aElemenetRotation = element->SourceRotation();
        }
    }

void CWsClientWindow::Scroll(const TRect &aClipRect, const TPoint &aOffset, const TRect &aRect)
	{
	if (iParent==NULL)
		OwnerPanic(EWservPanicParentDeleted);
	
//
	iRedraw->Scroll(aClipRect, aOffset,aRect);
//
	CWsTop::TriggerRedraws(RootWindow());
	}

void CWsClientWindow::DeleteBaseArea()
	{
	WS_ASSERT_DEBUG(iBaseArea!=&nullRegion, EWsPanicRegionNull);
 	if ((iCornerData&ECornerTypeMask)==EWindowCornerRegion)
		((RWsRegion *)iBaseArea)->Destroy();
	else
		{
		delete iBaseArea;
		}
 	iBaseArea=NULL;
	}

CWsClientWindow::~CWsClientWindow()
	{
	while(iVisibleRegionTrackingCounter>0)
		{
		SetupVisibleRegionTracking(EFalse);
		}
	if (iBaseWinFlags&EBaseWinNodeCreated)
		{
		MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
		if (windowTreeObserver)
			{
			windowTreeObserver->NodeReleased(*this);
			iBaseWinFlags &= ~EBaseWinNodeCreated;
			}
		}
	Shutdown();
	SetUserTransparentRegion(0);
	CWsPassword::WindowDestroyed(this);
	}

void CWsClientWindow::Shutdown()
//
// Destroy a window, disconnects from the window tree and destroys all it's child windows
//
	{
	iFlags|=EFlagShutDownInProgress;
	if (CClick::IsHandler())
		{
		TWindowCloseData params;
		params.iClientHandle=iClientHandle;
		//if parent already shutdown (or disconnected) send 0
		params.iWindowGroupId = (iParent) ? WinGroup()->Identifier() : 0;
		CClick::OtherEvent(EEventWindowClose,&params);
		}

	RemoveAllKeyRects();
	while(iWinGcList)
		iWinGcList->Deactivate();
//
	iFlags|=EFlagInvisible;		// First make it invisble
	if (iParent)				// In case window wasn't fully constructed
		ResetHiddenFlags();
//
	CWsWindow::Shutdown();
	DeleteBaseArea();
	CWsPointerBuffer::Disconnect(this);
	iFlags&=~EFlagShutDownInProgress;
	}

void CWsClientWindow::Activate()
	{
	if (iFlags&EFlagActive)
		OwnerPanic(EWservPanicWindowActive);
	iFlags|=EFlagActive;

	ResetHiddenFlags();

	MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
	if (windowTreeObserver)
		{
		windowTreeObserver->NodeExtentChanged(*this, FullRect());
		windowTreeObserver->NodeActivated(*this);
		}
	}

TBool CWsClientWindow::IsActivated() const
	{
	return (iFlags&EFlagActive)!=EFalse;
	}

void CWsClientWindow::SetCornerTypeL(TCornerType aCornerType, TInt aCornerFlags, TRegion *aNewBaseArea, TBool aNotifyShapeChanged)
	{
	TRegion *baseArea=NULL;
	if (aCornerFlags&ECornerTypeMask)
		OwnerPanic(EWservPanicCornerParams);
	
 	switch (aCornerType)
		{
		case EWindowCornerSquare:
			baseArea=new(ELeave) TRegionFix<1>();
			break;
		case EWindowCorner1:
			baseArea=new(ELeave) TRegionFix<3>();
			break;
		case EWindowCorner2:
		case EWindowCorner3:
			baseArea=new(ELeave) TRegionFix<5>();
			break;
		case EWindowCorner5:
			baseArea=new(ELeave) TRegionFix<9>();
			break;
		case EWindowCornerRegion:
			User::LeaveIfNull(baseArea=aNewBaseArea);
			baseArea->Offset(Origin());
			break;
		default:
			OwnerPanic(EWservPanicCornerParams);
		}
	DeleteBaseArea();
	iCornerData=aCornerType;
	iCornerData|=aCornerFlags;
	iBaseArea=baseArea;
	CalcBaseArea();
	ScheduleRegionUpdate(NULL);

	if ( aNotifyShapeChanged )
		{
		MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
		if (windowTreeObserver)
			{
			windowTreeObserver->AttributeChanged(*this, MWsWindowTreeObserver::EWindowShape);
			}
		}
	}

void CWsClientWindow::SetVisible(TBool aState)
	{
	if (aState)
		{
		if (iParent==NULL)
			OwnerPanic(EWservPanicParentDeleted);
		if (!(iFlags&EFlagInvisible))	// Already visible
			return;
		iFlags&=~EFlagInvisible;
		ResetHiddenFlags();
		}
	else
		{
		if (iFlags&EFlagInvisible || !iParent)	// Already invisible or parent has been deleted
			return;
		TWalkWindowTreePurgeEvents wwt;
		WalkWindowTree(wwt,EWalkChildren);		// Destroy all events on this and all children
		iFlags|=EFlagInvisible;
		ResetHiddenFlags();
		}
	
	MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
	if (windowTreeObserver)
		{
		windowTreeObserver->FlagChanged(*this, MWsWindowTreeObserver::EVisible, aState);
		}
	}

void CWsClientWindow::CommandL(TInt aOpcode, const TAny *aCmdData)
	{
#ifdef _DEBUG
	// Save root window for performing CheckTree at the end of this func.
	// When aOpcode is EWsWinOpFree, this object would've been destroyed
	// and a call to RootWindow() in that case would be impossible
	CWsRootWindow* rootWindow=RootWindow();
#endif
	TWsWinCmdUnion pData;
	pData.any=aCmdData;
	if (CWsWindowBase::CommandL(aOpcode,pData)==EFalse)
		{
		switch(aOpcode)
			{
			case EWsWinOpActivate:
				Activate();
				break;
			case EWsWinOpSetPos:
				SetExtentL(pData.pos,NULL);
				break;
			case EWsWinOpSetExtent:
			case EWsWinOpSetExtentErr:
				SetExtentL(&pData.SetEx->pos,&pData.SetEx->size);
				break;
			case EWsWinOpSetSize:
			case EWsWinOpSetSizeErr:
				SetExtentL(NULL,pData.size);
				break;
			case EWsWinOpInquireOffset:
				CWsClient::ReplyPoint(InquireOffset(*pData.UInt));
				break;
			case EWsWinOpPosition:
				CWsClient::ReplyPoint(iRel.iTl);
				break; 
			case EWsWinOpAbsPosition:
				CWsClient::ReplyPoint(iOrigin);
				break;
			case EWsWinOpSize:
				CWsClient::ReplySize(iRel.Size());
				break;
			case EWsWinOpTestInvariant:
				SetReply(EFalse);
				break;
			case EWsWinOpPointerFilter:
				{
				TUint old=iPointerFilter;
				iPointerFilter&=~pData.PointerFilter->mask;
				iPointerFilter|=pData.PointerFilter->mask&pData.PointerFilter->flags;
				if (old&EPointerFilterEnterExit)
					TWsPointer::ReLogWindow(this);
				}
				break;
			case EWsWinOpSetPointerGrab:
				if (*pData.Bool==EFalse)
					iFlags&=~EFlagPointerGrab;
				else
					iFlags|=EFlagPointerGrab;
				break;
			case EWsWinOpClaimPointerGrab:
				{
				if (!iParent)
					OwnerPanic(EWservPanicParentDeleted);		
				
				TInt errNo = TWsPointer::ClaimGrab(this,*pData.GrabControl);
				if(TWsWinCmdGrabControl::ESendReply & pData.GrabControl->flags)
					{
					// To avoid the reply-generated-flush, only do this for the new APIs, not the old ones.					
					SetReply(errNo);
					}
				}
				break;
			case EWsWinOpSetPointerCapture:
				iFlags&=~(EFlagPointerCaptured|EFlagPointerCaptureDragDrop|EFlagPointerCaptureAllGroups);
				if ((*pData.UInt)&RWindowBase::TCaptureFlagEnabled)
					{
					iFlags|=EFlagPointerCaptured;
					if ((*pData.UInt)&RWindowBase::TCaptureFlagDragDrop)
						iFlags|=EFlagPointerCaptureDragDrop;
					if ((*pData.UInt)&RWindowBase::TCaptureFlagAllGroups)
						iFlags|=EFlagPointerCaptureAllGroups;
					
					}
				TWsPointer::ReLogPointersCurrentWindows();
				break;
			case EWsWinOpSetPointerCapturePriority:
				iPointerCapturePriority=*pData.Int;
				break;
			case EWsWinOpGetPointerCapturePriority:
				SetReply(iPointerCapturePriority);
				break;
			case EWsWinOpSetVisible:
				SetVisible(*pData.Bool);
				break;
			case EWsWinOpScroll:
				{
				TPoint origin(0,0);
				TRect src(TRect(origin,iRel.Size()));
				src.Move(-pData.ScrollRect->offset);
				Scroll(TRect(origin,iRel.Size()),pData.ScrollRect->offset,src);
				}
				break;
			case EWsWinOpScrollClip:
				{
				TPoint origin(0,0);
				TRect src(TRect(origin,iRel.Size()));
				src.Move(-pData.ScrollRect->offset);
				TRect clip(pData.ScrollRect->clip);
				Scroll(clip,pData.ScrollRect->offset,src);
				}
				break;
			case EWsWinOpScrollRect:
				{
				TRect src(pData.ScrollRect->rect);
				Scroll(TRect(TPoint(0,0),iRel.Size()),pData.ScrollRect->offset,src);
				}
				break;
			case EWsWinOpScrollClipRect:
				{
				TRect src(pData.ScrollRect->rect);
				TRect clip(pData.ScrollRect->clip);
				Scroll(clip, pData.ScrollRect->offset,src);
				}
				break;
			case EWsWinOpSetOrdinalPositionPri:
				iOrdinalPriority=pData.OrdinalPos->ordinalPriority;
				SetOrdinalPosition(pData.OrdinalPos->pos);
				break;
			case EWsWinOpSetShadowHeight:
				OwnerPanic(EWservPanicOpcode); //this op code is deprecated, should never be generated by the client
				break;
			case EWsWinOpShadowDisabled:
				OwnerPanic(EWservPanicOpcode); //this op code is deprecated, should never be generated by the client
				break;
			case EWsWinOpRequiredDisplayMode:
				if (Backup()!=NULL)
					OwnerPanic(EWservPanicBackupDisplayMode);
				SetReply(SetRequiredDisplayModeL(*pData.DisplayMode));
				break;
			case EWsWinOpGetDisplayMode:
				SetReply(DisplayMode());
				break;
			case EWsWinOpRequestPointerRepeatEvent:
				{
				if (!iParent)
					OwnerPanic(EWservPanicParentDeleted);
				TInt errNo = TWsPointer::RequestPointerRepeatEvent(this,*pData.RequestPointerRepeatEvent);				
				if(TWsWinCmdRequestPointerRepeatEvent::ERepeatFlagsSendReply & pData.RequestPointerRepeatEvent->repeatFlags)
					{
					SetReply(errNo);
					}
				}
				break;
			case EWsWinOpCancelPointerRepeatEventRequest:
				{
				TInt errNo = TWsPointer::CancelPointerRepeatEventRequest(*pData.CancelPointerRepeatEventRequest);				
				if(TWsWinCmdCancelPointerRepeatEventRequest::ECancelRepeatFlagsSendReply & pData.RequestPointerRepeatEvent->repeatFlags)
					{
					SetReply(errNo);
					}
				}
				break;
			case EWsWinOpAllocPointerMoveBuffer:
				CWsPointerBuffer::ConnectL(this,pData.AllocPointerMoveBuffer->maxNumPoints,pData.AllocPointerMoveBuffer->flags);
				iFlags|=EFlagUsingPointerBuffer|EFlagHasPointerBuffer;
				break;
			case EWsWinOpFreePointerMoveBuffer:
				CWsPointerBuffer::Disconnect(this);
				iFlags&=~(EFlagUsingPointerBuffer|EFlagHasPointerBuffer);
				break;
			case EWsWinOpRetrievePointerMoveBuffer:
				CWsPointerBuffer::RetrievePointerMoveBuffer(this,*pData.Int);
				break;
			case EWsWinOpEnablePointerMoveBuffer:
				if (!(iFlags&EFlagHasPointerBuffer))
					OwnerPanic(EWservPanicNoPointerBuffer);
				iFlags|=EFlagUsingPointerBuffer;
				break;
			case EWsWinOpDisablePointerMoveBuffer: 
				iFlags&=~EFlagUsingPointerBuffer; 
				/*Fall Through*/
			case EWsWinOpDiscardPointerMoveBuffer:	
				CWsPointerBuffer::DiscardPointerMoveBuffer(this);
				break;
			case EWsWinOpAddKeyRect:
				AddKeyRectL(pData.AddKeyRect->rect, pData.AddKeyRect->scanCode, pData.AddKeyRect->activatedByPointerSwitchOn);
				break;
			case EWsWinOpRemoveAllKeyRects:
				RemoveAllKeyRects();
				break;
			case EWsWinOpPasswordWindow:
				if (!iParent)
					OwnerPanic(EWservPanicParentDeleted);
				CWsPassword::SetPasswordWindowL(this, *pData.PasswordMode);
				break;
			case EWsWinOpEnableBackup:
				if (!iParent)
					OwnerPanic(EWservPanicParentDeleted);
				if (*pData.UInt==0)
					iBackupsRequested|=EWindowBackupAreaBehind;		//For backwards compatibility
				else
					iBackupsRequested|=*pData.UInt;
				break;
			case EWsWinOpFadeBehind:
				{
				if (!iParent)
					OwnerPanic(EWservPanicParentDeleted);
				
				TUint8 blackMap;
				TUint8 whiteMap;
				iScreen->GetFadingParams(blackMap,whiteMap);
				SetFadeBehind(*pData.Bool);
				TWalkWindowTreeSetFaded wwt(*pData.Bool,this,blackMap,whiteMap);
				WalkWindowTree(wwt,EWalkBehind);
				}
				break;
			case EWsWinOpGetIsFaded:
				SetReply(iFadeCount);
				break;
			case EWsWinOpGetIsNonFading:
				SetReply(iFlags&EFlagNonFadingWindow);
				break;
			case EWsWinOpMoveToGroup:
				if (!iParent)
					OwnerPanic(EWservPanicParentDeleted);
				if (iParent->WinType()!=EWinTypeGroup)
					OwnerPanic(EWservPanicNotTopClient);
				((CWsTopClientWindow*)this)->DoMoveWindowL(*pData.Int);
				break;
			case EWsWinOpTestLowPriorityRedraw:
				{
				// This is purely for testing purposes
				// Returns the redraw priority
				TUint priority=0;
				TPckgBuf<TUint> priBuf;
				priority=WsOwner()->RedrawQueue()->RedrawPriority((CWsWindowRedraw*)this->iRedraw);
				priBuf()=priority;
				CWsClient::ReplyBuf(priBuf);
				}
				break;
			case EWsWinOpEnableVisibilityChangeEvents:
				iFlags |= EFlagGeneratesVisibilityEvents;
				SetupVisibleRegionTracking(ETrue);
				if (iFlags&EFlagActive)
					{
					iScreen->DoRedrawNow();
					PossibleVisibilityChangedEvent(ETrue);
					}
				break;
			case EWsWinOpDisableVisibilityChangeEvents:
				iFlags &= ~EFlagGeneratesVisibilityEvents;
				SetupVisibleRegionTracking(EFalse);
				break;
			case EWsWinOpSetTransparentRegion:
				{
				if (IsTranslucent())
					{
					TInt recs=*pData.Int;
	 				RWsRegion* reg=recs>0? GetRegionFromClientL(iWsOwner,recs) : new(ELeave) RWsRegion;
	 				SetUserTransparentRegion(reg);
					SetReply(KErrNone);
					}
				else
					{
					OwnerPanic(EWservPanicTransparencyObjNotCreated);	
					}				
				}
				break;
			case EWsWinOpSetTransparencyPolicy:
				{
				if (IsTranslucent())
					SetReply(KErrNone);
				else
					OwnerPanic(EWservPanicTransparencyObjNotCreated);
				}
				break;
			case EWsWinOpSetTransparencyAlphaChannel:
				{
				iFlags |= static_cast<TUint>(EFlagHasAlpha);
				SetReply(KErrNone);
				
				MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
				if (windowTreeObserver)
					{
					windowTreeObserver->FlagChanged(*this, MWsWindowTreeObserver::EAlphaChannelTransparencyEnabled, ETrue);
					}
				break;
				}			
			default:
				if (iRedraw->CommandL(aOpcode,pData)==EFalse)
					{
					OwnerPanic(EWservPanicOpcode);
					}
			}
		}
#if defined(_DEBUG)
	rootWindow->CheckTree();
#endif
	}

void CWsClientWindow::GcActivated(CWsGc *aGc)
	{
	aGc->SetNextWinGc(iWinGcList);
	iWinGcList=aGc;
	}

void CWsClientWindow::GcDeactivated(CWsGc *aGc)
	{
	if (aGc==iWinGcList)
		iWinGcList=aGc->NextWinGc();
	else
		{
		CWsGc *gc=iWinGcList;
		CWsGc *next;
		FOREVER
			{
			next=gc->NextWinGc();
			WS_ASSERT_DEBUG(next!=NULL, EWsPanicBadActiveGcList);
			if (next==aGc)
				{
				gc->SetNextWinGc(next->NextWinGc());
				break;
				}
			gc=next;
			}
		}
	aGc->SetNextWinGc(NULL);
	}

void CWsClientWindow::ReactivateGcs()
	{
	for (CWsGc * gc = iWinGcList; gc; gc = gc->NextWinGc())
		{
		gc->Reactivate();
		}
	}

void CWsClientWindow::OffsetUserTransparentRegion(const TPoint& aOffset)
	{
	if (iUserDefinedTransparentRegion)
		{
		iUserDefinedTransparentRegion->Offset(aOffset);
		}	
	}

void CWsClientWindow::SetUserTransparentRegion(RWsRegion* aRegion)
	{
	if (iUserDefinedTransparentRegion)
		{
		iUserDefinedTransparentRegion->Close();
		delete iUserDefinedTransparentRegion;
		iUserDefinedTransparentRegion = 0;
		}
		
	if (aRegion)
		{		
		aRegion->Offset(iOrigin);
		iUserDefinedTransparentRegion=aRegion;
		}
		
	SetUserOpaqueRegion();
	}

void CWsClientWindow::SetUserOpaqueRegion()
	{
	if (iUserDefinedOpaqueRegion)
		{
		iUserDefinedOpaqueRegion->Close();
		delete iUserDefinedOpaqueRegion;
		iUserDefinedOpaqueRegion = 0;
		}
	if (iUserDefinedTransparentRegion)
		{
		iUserDefinedOpaqueRegion=new RWsRegion;
		if (iUserDefinedOpaqueRegion)
			{
			iUserDefinedOpaqueRegion->Copy(*iBaseArea);
			iUserDefinedOpaqueRegion->SubRegion(*iUserDefinedTransparentRegion);
			if (iUserDefinedOpaqueRegion->CheckError() || iUserDefinedOpaqueRegion->Count() == 0)
				{
				iUserDefinedOpaqueRegion->Close();
				delete iUserDefinedOpaqueRegion;
				iUserDefinedOpaqueRegion = 0;
				}
			}
		// Intentionally not sending this notification during destruction (when SetUserTransparentRegion is called from d'tor)
		MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
		if (windowTreeObserver)
			{
			windowTreeObserver->TransparentRegionChanged(*this, *iUserDefinedTransparentRegion, iUserDefinedOpaqueRegion);
			}
		}
	}

/** Checks whether this window is in front of aWin.

@param aWin A window.
@return EFalse if aWin is the same or is in front of this, ETrue otherwise.
@internalComponent
* released
*/	
TBool CWsClientWindow::IsInfrontOf(const CWsWindowBase* aWin) const
	{
	TInt thisDepth=Depth();
	TInt otherDepth=aWin->Depth();
	const CWsWindowBase *thisWin=this;
	const CWsWindowBase *otherWin=aWin;
	if (thisDepth>otherDepth)
		{
		for (TInt count=thisDepth-otherDepth;count>0;count--)
			thisWin=thisWin->BaseParent();
		}
	else
		{
		for (TInt count=otherDepth-thisDepth;count>0;count--)
			otherWin=otherWin->BaseParent();
		}
	if (thisWin==otherWin)
		return thisDepth>otherDepth;
	while(thisWin->BaseParent()!=otherWin->BaseParent())
		{
		thisWin=thisWin->BaseParent();
		otherWin=otherWin->BaseParent();
		}
	const CWsWindowBase *win=thisWin->BaseParent()->BaseChild();
	FOREVER
		{
		if (win==otherWin)
			{
			return EFalse;
			}
		if (win==thisWin)
			return ETrue;
		win=win->NextSibling();
		}
	}
	
CWsTopClientWindow* CWsClientWindow::TopClientWindow()
	{
	if (iParent==NULL)
		OwnerPanic(EWservPanicParentDeleted);
	CWsWindowBase* win=this;
	while(win->BaseParent()->WinType()!=EWinTypeGroup)
		win=win->BaseParent();
	return static_cast<CWsTopClientWindow*>(win);
	}

const TRegion &CWsClientWindow::InvalidArea() const
	{
	return(iRedraw->InvalidArea());
	}


TUint CWsClientWindow::RedrawPriority(TInt *aShift) const
	{
	TUint ordinalPos=OrdinalPosition(EFalse)+1;
	if (ordinalPos>15)	// Algorithm only works upto 15 , make all windows after 15 equal in priority
		ordinalPos=15;
	TInt shift;
	TUint parent=((CWsClientWindow *)iParent)->RedrawPriority(&shift);
	if (shift>0)
		shift--;
	if (aShift)
		*aShift=shift;
	return(parent+(ordinalPos<<(shift*KWinRedrawPriBitsPerLevel)));
	}

TDblQue<TPointerKeyList> *CWsClientWindow::PointerKeyList() const
	{
	return(iPointerKeyList);
	}

void CWsClientWindow::AddKeyRectL(const TRect &aRect, TInt aScanCode, TBool aActivatedByPointerSwitchOn)
	{
	if (!iPointerKeyList)
		iPointerKeyList=new(ELeave) TDblQue<TPointerKeyList>(_FOFF(TPointerKeyList,iQue));
	TPointerKeyList *pkl=new(ELeave) TPointerKeyList();
	iPointerKeyList->AddLast(*pkl);
	pkl->iRect=aRect;
	pkl->iScanCode=aScanCode;
	pkl->iActivatedByPointerSwitchOn=aActivatedByPointerSwitchOn;
	}

void CWsClientWindow::RemoveAllKeyRects()
	{
	if (iPointerKeyList)
		{
		TPointerKeyList *pkl=NULL;
		for(TDblQueIter<TPointerKeyList> iter(*iPointerKeyList);(pkl=iter++)!=NULL;)
			{
			pkl->iQue.Deque();
			delete pkl;
			}
		delete iPointerKeyList;
		iPointerKeyList=NULL;
		}
	}

TBool CWsClientWindow::IsHidden()
	{
	return (!IsVisible()) || VisibleRegion().IsEmpty();
	}

void CWsClientWindow::SetFaded(TBool aFade, TUint8 aBlackMap, TUint8 aWhiteMap, TBool aNotifyObserver)
	{
	TBool stateChanged;
	SetFaded(aFade, aBlackMap, aWhiteMap, aNotifyObserver, stateChanged);
	}

void CWsClientWindow::SetFaded(TBool aFade, TUint8 aBlackMap, TUint8 aWhiteMap, TBool aNotifyObserver, TBool& aStateChanged)
	{
	iBlackMap=aBlackMap;
	iWhiteMap=aWhiteMap;
	const TBool mapAltered = (iBlackMap != aBlackMap) || (iWhiteMap != aWhiteMap); 
	const TInt oldFadeCount = iFadeCount;

	if (iAbsoluteFading) 
		{ 
		if (aFade) 
			{ 
			iFadeCount = 1; 
			} 
		else 
			{ 
			iFadeCount = 0; 
			} 
		} 
	else 
		{ 
		if (aFade) 
			{ 
			++iFadeCount; 
			} 
		else if (iFadeCount > 0) 
			{ 
			--iFadeCount; 
			} 
		}
	
	//Fade state only changes when iFadeCount transitions from 0 to 1 or from 1 to 0.
 	aStateChanged = (iFadeCount==0 || oldFadeCount==0) && (oldFadeCount != iFadeCount);
 	if (!Screen()->ChangeTracking() && CWsTop::IsFadeEnabled() && (aStateChanged || mapAltered) ) 
 		{
 		Screen()->AcceptFadeRequest(this, (iFadeCount > 0));
 		}

	const TBool doNotify = iAbsoluteFading ? aStateChanged : (oldFadeCount != iFadeCount);
	MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
	if (windowTreeObserver && aNotifyObserver && doNotify)
		{
		windowTreeObserver->FadeCountChanged(*this, iFadeCount);
		}	
	}

void CWsClientWindow::ResetHiddenFlagsInParentAndChildren()
	{
	ResetHiddenFlag();
	SetElementOpacity(IsVisible() ? 0xFF : 0x00);	// Update element visibility
	for(CWsClientWindow* child=Child();child;child=child->NextSibling())
		{
		child->ResetHiddenFlagsInParentAndChildren();
		}
	}

const TRegion& CWsClientWindow::WindowArea() const
	{
	WS_ASSERT_DEBUG(iBaseArea, EWsPanicRegionNull);
	return *iBaseArea;
	}

void CWsClientWindow::Invalidate(const TRect * aRect)
	{
	iRedraw->Invalidate(aRect);
	}

void CWsClientWindow::ScheduleRegionUpdate(const TRegion* aDefinitelyDirty)
	{
	if (IsVisible())
		{
		iScreen->ScheduleRegionUpdate(aDefinitelyDirty);
		}
	}

void CWsClientWindow::AddRedrawRegion(const TRegion& aRegion, TBool aSchedule, TRedrawDepth aDepth)
	{
	if (!IsHidden())
		{
		iScreen->AddRedrawRegion(aRegion, aSchedule, aDepth);
		}
	}

void CWsClientWindow::SendState(MWsWindowTreeObserver& aWindowTreeObserver) const
	{	
	CWsWindow::SendState(aWindowTreeObserver);
	
	if(iFadeCount > 0)
		{
		aWindowTreeObserver.FadeCountChanged(*this, iFadeCount);
		}
	
	if(iUserDefinedTransparentRegion)
		{
		aWindowTreeObserver.TransparentRegionChanged(*this, *iUserDefinedTransparentRegion, iUserDefinedOpaqueRegion);
		}

	if(HasElement())
		{
		CWindowElementSet& windowElementSet = Screen()->WindowElements();
		const TBackgroundAttributes		*bElementAttr;
		const RArray<TPlacedAttributes>	*pElementsAttr;
		
		TInt ret = windowElementSet.FindElements(*this, bElementAttr, pElementsAttr);
		if(ret == KErrNone)
			{
			MWsElement* element = bElementAttr->iElement;
			if (element)
				aWindowTreeObserver.ElementAdded(*this, *element);
			}
		}
	
	}

TBool CWsClientWindow::IsDSAHost() const
	{
	TBool res = CWsWindow::IsDSAHost();
	if ( !res )
		{ // check for grace period when DSA is being restarted (after aborting but before client started DSA again)
		res = Screen()->IsDSAClientWindow( this );
		}
	return res;
	}

void CWsClientWindow::UpdateElementExtent(const TPoint* aOffset)
	{
	if (Redraw()->HasElement())
		{
		Screen()->WindowElements().UpdateElementExtent(*this, aOffset);
		}
	}

void CWsClientWindow::SetElementOpacity(TInt aOpacity)
	{
	if (Redraw()->HasElement())
		{
		Screen()->WindowElements().SetElementOpacity(*this,aOpacity);

		} 
	}

TRect CWsClientWindow::GetOriginalSrcElementRect() const
    {
    return iOriginalSrcElementRect;
    }
TRect CWsClientWindow::GetOriginalDestElementRect() const
    {
    return iOriginalDestElementRect;
    }
    
//
// Code for CWsTopClientWindow, a client window that connects to a group window //
//

CWsTopClientWindow::CWsTopClientWindow(CWsClient* aOwner, CScreen* aScreen) : CWsClientWindow(aOwner, aScreen)
	{
	}

void CWsTopClientWindow::ConstructL(const TWsClCmdCreateWindow &cmd, CWsWindowBase *aParent, TBool aScreenDeviceIsInvalid)
	{
	iFlags|=EFlagIsTopClientWindow;
	CWsClientWindow::ConstructL(cmd, aParent, aScreenDeviceIsInvalid);
	}

void CWsTopClientWindow::SetInactive()
	{
	iFlags&=~EFlagActive;
	ResetHiddenFlags();
	}

void CWsTopClientWindow::SetScreenDeviceValidState(TBool aState)
	{
	if (SetScreenDeviceValidStateFlag(aState))
		ResetHiddenFlags();
	}

TBool CWsTopClientWindow::SetScreenDeviceValidStateFlag(TBool aState)
	{
	TBool isSet=iFlags&EFlagScreenDeviceInvalid;
	if (!isSet==!aState)
		{
		if (aState)
			iFlags&=~EFlagScreenDeviceInvalid;
		else
			iFlags|=EFlagScreenDeviceInvalid;
		return ETrue;
		}
	return EFalse;
	}

void CWsTopClientWindow::SetOrdinalPosition(TInt aPos)
	{
	if (!iParent)
		{
		OwnerPanic(EWservPanicParentDeleted);
		}
	if (CheckOrdinalPositionChange(aPos))
		{
		CWsWindowBase::SetOrdinalPosition(aPos);
		CWsTop::TriggerRedraws(RootWindow());
		}
	}

void CWsTopClientWindow::DoMoveWindowL(TInt aIdentifier)
	{
	CWsWindowGroup* group=CWsWindowGroup::WindowGroupFromIdentifierL(aIdentifier);
	if (group==iParent)
		return;
	if (group->WsOwner()!=WsOwner())
		User::Leave(KErrNotFound);
	ChangeWindowPosition(0, group);
	CWsTop::TriggerRedraws(RootWindow());
	}

TUint CWsTopClientWindow::RedrawPriority(TInt *aShift) const
	{
	TUint ordinalPos=OrdinalPosition(EFalse);
	if (ordinalPos>KWinRedrawPriMaxOrdinal)	// Algorithm only works for upto KWinRedrawPriMaxOrdinal windows,
		ordinalPos=KWinRedrawPriMaxOrdinal;	// make all windows after this equal in priority
	if (aShift)
		*aShift=KWinRedrawPriMaxLevel;
	return(ordinalPos<<(KWinRedrawPriMaxLevel*KWinRedrawPriBitsPerLevel));
	}

