// Copyright (c) 1995-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:
// Root window sub-class of CWsWindow
// 
//

#include "rootwin.h"
#include <e32std.h>
#include <graphics/wsscreendevice.h>
#include "server.h"
#include "windowgroup.h"
#include "walkwindowtree.h"
#include "wstop.h"
#include "ScrDev.H"
#include "panics.h"
#include "inifile.h"
#include "EVENT.H"

_LIT(KNoBlank,"NOBLANKSCREEN");
_LIT(KDefaultBackgroundColor,"BACKGROUNDCOLOR");
_LIT(KDefaultBackgroundAlpha,"BACKGROUNDALPHA");
_LIT(KRootWinDefaultBackgroundColor,"ROOTBACKGROUNDCOLOR");

CWsRootWindow::CWsRootWindow(CWsClient* aOwner, CScreen* aScreen) : CWsWindow(aOwner,WS_HANDLE_ROOT_WINDOW,aScreen)
	{
	iWinType=EWinTypeRoot;
	}

CWsRootWindow::~CWsRootWindow()
	{
	if (Screen() && (iBaseWinFlags&EBaseWinNodeCreated))
		{
		MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
		if (windowTreeObserver)
			{
			windowTreeObserver->NodeReleased(*this);
			iBaseWinFlags &= ~EBaseWinNodeCreated;
			}
		}
	Shutdown();
	}

void CWsRootWindow::ConstructL()
	{
	CWsWindow::Construct();
	iParent=NULL;
	iSibling=NULL;
	iChild=NULL;
	iClientHandle=NULL;
	iAbs.Resize(iScreen->SizeInPixels());
	iRel=iAbs;
	iFlags=EFlagPointerCaptured;
	iPointerFilter=EPointerFilterEnterExit|EPointerFilterMove|EPointerFilterDrag;
	iArea.AddRect(iAbs);
	iRedraw=new(ELeave) CWsBlankWindow(this);
	iRedraw->ConstructL();
	TInt backgroundcolor;
	if(!WsIniFile->FindVar(KDefaultBackgroundColor,backgroundcolor))
		backgroundcolor = KRgbWhite.Value();
	TInt backgroundalpha;
	if(!WsIniFile->FindVar(KDefaultBackgroundAlpha,backgroundalpha))
		backgroundalpha = 0xFF;	
	iDefaultBackgroundColor = TRgb(backgroundcolor,backgroundalpha);
	
	if (WsIniFile->FindVar(KNoBlank))
		BlankRedraw()->SetBackgroundClear();
	else
		{
		if (WsIniFile->FindVar(KRootWinDefaultBackgroundColor,backgroundcolor))
			SetColor(TRgb(backgroundcolor,backgroundalpha));
		else
			SetColor(iDefaultBackgroundColor);
		}

	MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
	if (windowTreeObserver)
		{
		windowTreeObserver->NodeCreated(*this, NULL);
		iBaseWinFlags |= EBaseWinNodeCreated;
		}
	}

void CWsRootWindow::SetColor(TRgb aColor)
	{
	BlankRedraw()->SetColor(aColor);
	}

void CWsRootWindow::SetColorIfClear()
	{
	if (!BlankRedraw()->IsBackgroundColor())
		SetColor(iDefaultBackgroundColor);
	}

const CWsWindow *CWsRootWindow::PointerWindow(const TPoint &aInPos,TPoint *aOutPos, TPoint *aParentPos,
					const CWsWindow *aGrabWin, const CWsWindow *&aOriginalWinItIsIn, const CWsWindowGroup *aForceInGroup)
//
// For aInPos (a global point on screen) find which window it is in, starting the search from 'this'.
// aOutPos is set to be aInPos adjusted relative to the top left of the result window.
// If the pointer is not in any of the searched windows the result is returned as though it was in 'this'
// even though it may actually be oustside the bounds of this.
//
// If aForceInGroup==NULL search all groups otherwise only search it only
//
	{
	aOriginalWinItIsIn=this;
	const CWsWindowGroup *group;
	const CWsWindowGroup *winItIsInGroup=aForceInGroup;
//
// First determine owner of the window the event is in regardless of any capture
// This is so we can decide whether the capture affects this case or not
//
	for(group=(aForceInGroup ? aForceInGroup:Child());group!=NULL;group=group->NextSibling())
		{
		CWsClientWindow *win=group->Child();
		while(win!=NULL)
			{

			if (win->IsVisible() && win->PointerHit(aInPos))
				{
				aOriginalWinItIsIn=win;
				winItIsInGroup=group;
				win=win->Child();
				}
			else
				win=win->NextSibling();
			}
		if (aOriginalWinItIsIn!=this || aForceInGroup!=NULL)
			break;
		}
//
// Then try again taking note of any pointer capture or grab
//
	const CWsWindow *winItIsIn;
	if (aGrabWin!=NULL)
		winItIsIn=aGrabWin;
	else
		{
		winItIsIn=this;
		for(group=(aForceInGroup ? aForceInGroup:Child());group!=NULL;group=group->NextSibling())
			{
			CWsClientWindow *win=group->Child();
			while(win!=NULL)
				{
				const TBool underTheSameGroup=winItIsInGroup==group;
				if (win->IsVisible() && 
					((win->iFlags&EFlagPointerCaptured && 
					 ((!underTheSameGroup && win->iFlags&EFlagPointerCaptureAllGroups) || 
					  (winItIsInGroup==NULL && group==CWsTop::FocusWindowGroup()) || 
					  (underTheSameGroup && win->iPointerCapturePriority>=aOriginalWinItIsIn->iPointerCapturePriority)))
					   || win->PointerHit(aInPos)))
					{
				 	winItIsIn=win;
					win=win->Child();
					}
				else
					win=win->NextSibling();
				}
			if (winItIsIn!=this || aForceInGroup!=NULL)
				break;
			}
		}
	if (aOutPos!=NULL)
		{
		*aOutPos=aInPos-winItIsIn->iOrigin;
		}
	if (aParentPos!=NULL)
		{
		const CWsWindowBase *win=winItIsIn->BaseParent();
		if (win==NULL)
			win=winItIsIn;
		*aParentPos=aInPos-win->Origin();
		}
	return(winItIsIn);
	}

void CWsRootWindow::GenerateWindowRegion(RWsRegion &aRegion) const
	{
	aRegion.Clear();
	aRegion.AddRect(iAbs);
	if (iChild)
		{
		for(CWsTopClientWindow *win=FirstTopClientWindow();aRegion.Count()>0 && win!=NULL;win=win->NextSiblingMultiParent())
			{
			if (win->IsVisible())
				aRegion.SubRegion(*win->BaseArea());
			}
		}
	}

void CWsRootWindow::CommandL(TInt , const TAny *)
	{
	WS_PANIC_ALWAYS(EWsPanicRootCommand);
	}

void CWsRootWindow::InvalidateWholeScreen()
	{
	RWsRegion screen(iAbs);
	Invalidate(&screen);
	screen.Close();
	}

void CWsRootWindow::Invalidate(RWsRegion* aRegion)
	{
	iScreen->AddRedrawRegion(*aRegion);
	}

void CWsRootWindow::AdjustCoordsDueToRotation()
	{
	iArea.Clear();
	iAbs=iScreen->DrawableArea();
	iRel=iAbs;
	iArea.AddRect(iAbs);
	iOrigin=iAbs.iTl;
	for(CWsTopClientWindow *win=FirstTopClientWindow();win!=NULL;win=win->NextSiblingMultiParent())
		{
		win->RecalcChildAbs(NULL);
		}
	}

void CWsRootWindow::ClearDisplay()
	{
	MWsScreenDevice *sd=static_cast<MWsScreenDevice*>(iScreen->ResolveObjectInterface(KMWsScreenDevice));
	WS_ASSERT_ALWAYS(sd, EWsPanicScreenDeviceMissing); 
	sd->ClearDisplay(BackColor());	
	}

void CWsRootWindow::SetSystemFaded(TBool aFaded, TUint8 aBlackMap, TUint8 aWhiteMap)
	{
	WS_ASSERT_DEBUG(Screen(),EWsPanicNoScreen);
	
	TBool stateChanged = EFalse; //will be set to true if one or more windows change fade state.
	for(CWsWindowGroup* win=Child();win!=NULL;win=win->NextSibling())
		{
		TWalkWindowTreeSetSystemFaded wwt(aFaded, win, aBlackMap, aWhiteMap, stateChanged);
		win->WalkWindowTree(wwt,EWalkChildren);
		}

	MWsWindowTreeObserver* windowTreeObserver = Screen()->WindowTreeObserver();
	if(windowTreeObserver && stateChanged)
		{
		windowTreeObserver->FadeAllChildren(*this, aFaded);
		}
	}

CWsWindowGroup* CWsRootWindow::WindowGroup(TInt aWindowGroup)
	{
	CWsWindowBase* group=iChild;
	while (aWindowGroup-->0 && group)
		group=group->NextSibling();
	return static_cast<CWsWindowGroup*>(group);
	}

CWsTopClientWindow *CWsRootWindow::FirstTopClientWindow() const
	{
	CWsWindowGroup* group;
	for(group=Child();group && group->Child()==NULL;group=group->NextSibling())
		{}
	return(group?group->Child():NULL);
	}

const TRegion& CWsRootWindow::WindowArea() const
	{
	return iArea;
	}

void CWsRootWindow::SendState(MWsWindowTreeObserver& aWindowTreeObserver) const
	{
	aWindowTreeObserver.NodeCreated(*this, NULL);
	}

/** @see MWsWindowTreeNode */
const MWsWindow* CWsRootWindow::Window() const
	{
	return NULL;
	}

