// 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:
// Window virtual base class, windows and window groups are derived from this
//
//
#include <e32std.h>
#include "server.h"
#include "winbase.h"
#include "rootwin.h"
#include "windowgroup.h"
#include "walkwindowtree.h"
#include "wstop.h"
#include "EVQUEUE.H"
#include "EVENT.H"
#include "panics.h"
#include "pointer.h"
#include "windowelementset.h"
CWsWindowBase::CWsWindowBase(CWsClient* aOwner,WH_HANDLES aType, CScreen* aScreen) : CWsScreenObject(aOwner,aType,aScreen)
{
}
void CWsWindowBase::ConstructL(CWsWindowBase *aParent)
{
iParent=aParent;
iSibling=aParent->iChild;
aParent->iChild=this;
CScreen* screen = aParent->Screen();
WS_ASSERT_DEBUG(screen,EWsPanicNoScreen);
MWsWindowTreeObserver* const windowTreeObserver = screen->WindowTreeObserver();
if (windowTreeObserver)
{
windowTreeObserver->NodeCreated(*this, ParentNode());
iBaseWinFlags |= EBaseWinNodeCreated;
}
SetOrdinalPosition(0);
iFadeCount = iParent->iFadeCount;
}
CWsWindowBase *CWsWindowBase::GetPrevSibling() const
{
if(iParent == NULL) //RootWindow
return(NULL);
CWsWindowBase* prev=iParent->iChild;
CWsWindowBase *ret=NULL;
while (prev!=this)
{
ret=prev;
prev=prev->iSibling;
}
return(ret);
}
CWsWindowBase *CWsWindowBase::LastSibling() const
{
const CWsWindowBase *win;
for(win=this;win->iSibling;win=win->iSibling)
{}
return (CWsWindowBase*)win;
}
CWsWindowBase *CWsWindowBase::PrevSiblingMultiParent() const
{
CWsWindowBase *win=GetPrevSibling();
if (win)
return(win);
for(CWsWindowBase *parent=iParent->GetPrevSibling();parent;parent=parent->GetPrevSibling())
if ((win=parent->iChild)!=NULL)
return(win->LastSibling());
return(NULL);
}
CWsWindowBase *CWsWindowBase::NextSiblingMultiParent() const
{
if (iSibling)
return(iSibling);
for(CWsWindowBase *parent=iParent->iSibling;parent;parent=parent->iSibling)
{
if (parent->iChild!=NULL)
return(parent->iChild);
}
return(NULL);
}
TInt CWsWindowBase::OrdinalPosition(TBool aFull) const
{
if (!iParent)
{
OwnerPanic(EWservPanicParentDeleted);
}
CWsWindowBase *win=iParent->iChild;
if (!aFull)
while(iOrdinalPriority<win->iOrdinalPriority)
win=win->iSibling;
TInt count;
for(count=0;win!=this;count++)
win=win->iSibling;
return(count);
}
/** Removes a window from the list of siblings maintained by its parent window.
The iSibling stored inside the window we remove is kept unchanged as it may be needed later.
@internalComponent
@released
*/
void CWsWindowBase::RemoveFromSiblingList()
{
if (iParent!=NULL)
{
CWsWindowBase **prev= &iParent->iChild;
while ((*prev)!=this)
prev= &(*prev)->iSibling;
*prev=iSibling;
}
}
CWsWindowGroup *CWsWindowBase::WinGroup() const
{
if (iWinType==EWinTypeClient)
return(((CWsClientWindow *)this)->TopClientWindow()->Parent());
if (iWinType==EWinTypeGroup)
return((CWsWindowGroup *)this);
return(NULL);
}
TBool CWsWindowBase::CheckOrdinalPositionChange(TInt aPos)
//
// This routine checks to see whether the specified new ordinal position
// will causes a change, if so returns ETrue else EFalse.
//
{
CWsWindowBase *win= iParent->iChild;
CWsWindowBase *prev= NULL;
while(win==this || (win!=NULL && iOrdinalPriority<win->iOrdinalPriority))
{
prev=win;
win=win->iSibling;
}
if (prev==this)
win=this;
else if (win==NULL || (win->iSibling==this && iOrdinalPriority>win->iOrdinalPriority))
return ETrue;
while(aPos--!=0 && win->iSibling!=NULL && iOrdinalPriority==win->iSibling->iOrdinalPriority)
win=win->iSibling;
return(win!=this);
}
void CWsWindowBase::ChangeWindowPosition(TInt aPos,CWsWindowBase* aNewParent)
{
TBool changedWindowGroup = EFalse;
WS_ASSERT_DEBUG(aNewParent,EWsPanicWindowNull);
if (aNewParent != iParent)
{
iScreen->ScheduleRegionUpdate(NULL);
TWalkWindowTreeScheduleRedraws wwt;
WalkWindowTree(wwt, EWalkChildren);
changedWindowGroup = ETrue;
}
else if (WinType() == EWinTypeClient)
{
CWsClientWindow * cliwin = static_cast<CWsClientWindow*>(this);
if (cliwin->IsVisible())
{
iScreen->ScheduleRegionUpdate(NULL);
if (cliwin->IsTranslucent())
{
// There is still room for optimization here. These redraws are only required if the window
// moved through another window and BOTH of them were transparent, otherwise the visible
// region change will sort out the redraws required.
TWalkWindowTreeScheduleRedraws wwt;
WalkWindowTree(wwt, EWalkChildren);
}
}
}
else if (WinType() == EWinTypeGroup)
{
iScreen->ScheduleRegionUpdate(NULL);
if (static_cast<CWsWindowGroup*>(this)->HasVisibleTranslucentChild())
{
TWalkWindowTreeScheduleRedraws wwt;
WalkWindowTree(wwt, EWalkChildren);
}
}
RemoveFromSiblingList();
CWsWindowBase **prevWinPtr= &aNewParent->iChild;
while((*prevWinPtr)!=NULL && iOrdinalPriority<(*prevWinPtr)->iOrdinalPriority)
{
prevWinPtr= &(*prevWinPtr)->iSibling;
}
while(aPos--!=0 && *prevWinPtr!=NULL && iOrdinalPriority==(*prevWinPtr)->iOrdinalPriority)
{
prevWinPtr= &(*prevWinPtr)->iSibling;
}
iSibling=*prevWinPtr;
iParent=aNewParent;
*prevWinPtr=this;
Screen()->WindowElements().SortByZOrder();
MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
if (windowTreeObserver)
{
if(changedWindowGroup && (WinType() == EWinTypeClient))
{
windowTreeObserver->MovedToWindowGroup(*this, *(this->WinGroup()));
}
else if(!changedWindowGroup)
{
windowTreeObserver->SiblingOrderChanged(*this, OrdinalPosition(ETrue));
}
else if(changedWindowGroup)
{
OwnerPanic(EWservPanicInvalidParameter); //Should be impossible to end up here as only WinType() EWinTypeClient
} //and EWinTypeGroup can be moved to another windowgroup.
} //@see RWindowBase::MoveToGroup
}
void CWsWindowBase::SetOrdinalPosition(TInt aPos)
{
if (CheckOrdinalPositionChange(aPos))
ChangeWindowPosition(aPos,iParent);
}
TEventQueueWalkRet EventPurgeFunc(TAny *aPtr, TWsEvent *aEvent)
//
// Callback function for event queue walk
//
{
return(((CWsWindowBase *)aPtr)->EventPurgeCheck(aEvent));
}
TEventQueueWalkRet CWsWindowBase::EventPurgeCheck(TWsEvent *aEvent)
{
if (aEvent->Handle()==ClientHandle())
return(EEventQueueWalkDeleteEvent);
return(EEventQueueWalkOk);
}
void CWsWindowBase::PurgeEvents()
{
iWsOwner->EventQueue()->WalkEventQueue(&EventPurgeFunc,this);
}
void CWsWindowBase::Shutdown()
//
// Destroy a window, disconnects from the window tree and destroys all it's child windows
//
{
if (iWsOwner!=NULL)
PurgeEvents();
if (iParent!=NULL) // Check it's connected to something
{
CWsWindowBase *win;
for(win=this;win && win->iParent!=(CWsWindowBase *)RootWindow();win=win->iParent)
{}
RemoveFromSiblingList();
TWalkWindowTreeDisconnect wwt2(win ? ((CWsWindowGroup *)win)->TextCursor() : NULL);
WalkWindowTree(wwt2,EWalkChildren); // Disconnect all child windows
iChild=NULL;
}
TWindowServerEvent::RemoveFromSwitchOnEventList(*this);
TWindowServerEvent::RemoveFromErrorMessageList(*this);
TWindowServerEvent::RemoveFromGroupChangeEventEventList(*this);
TWindowServerEvent::RemoveFromFocusChangeEventEventList(*this);
TWindowServerEvent::RemoveFromGroupListChangeEventEventList(*this);
TWindowServerEvent::RemoveFromModifierChangedEventList(*this);
TWindowServerEvent::RemoveFromScreenDeviceChangeEventList(*this);
CWsTop::StopWindowGettingOffEvents(this);
}
TBool CWsWindowBase::CommandL(TInt aOpcode, TWsWinCmdUnion &aCmd)
//
// If the command is supported by the window base class process it and return ETrue
// if it is not supported return EFalse
//
{
switch(aOpcode)
{
case EWsWinOpFree:
{
delete this;
break;
}
case EWsWinOpSetOrdinalPosition:
SetOrdinalPosition(*aCmd.Int);
break;
case EWsWinOpOrdinalPriority:
SetReply(iOrdinalPriority);
break;
case EWsWinOpOrdinalPosition:
SetReply(OrdinalPosition(EFalse));
break;
case EWsWinOpFullOrdinalPosition:
SetReply(OrdinalPosition(ETrue));
break;
case EWsWinOpClientHandle:
SetReply(iClientHandle);
break;
case EWsWinOpParent:
if (!iParent)
{
OwnerPanic(EWservPanicParentDeleted);
}
SetReply(iParent->iClientHandle);
break;
case EWsWinOpPrevSibling:
{
if (!iParent)
{
OwnerPanic(EWservPanicParentDeleted);
}
TUint32 reply=NULL;
for(CWsWindowBase *win=this->GetPrevSibling();win;win=win->GetPrevSibling())
{
if (win->iWsOwner==iWsOwner)
{
reply=win->iClientHandle;
break;
}
}
SetReply(reply);
}
break;
case EWsWinOpNextSibling:
{
TUint32 reply=NULL;
for(CWsWindowBase *win=this->iSibling;win;win=win->iSibling)
{
if (win->iWsOwner==iWsOwner)
{
reply=win->iClientHandle;
break;
}
}
SetReply(reply);
}
break;
case EWsWinOpChild:
SetReply(iChild==NULL ? NULL : iChild->iClientHandle);
break;
case EWsWinOpScreenNumber:
SetReply(Screen()->ScreenNumber());
break;
case EWsWinOpWindowGroupId:
{
TUint32 reply=NULL;
CWsWindowGroup *wg=WinGroup();
if (wg)
{
reply=wg->Identifier();
}
SetReply(reply);
}
break;
case EWsWinOpEnableOnEvents:
{
const TEventControl circumstances = *aCmd.EventControl;
TWindowServerEvent::AddToSwitchOnEventListL(*this, circumstances);
if (iScreen->ChangeTracking())
{
if(circumstances & EEventControlOnlyWhenVisible)
{
TWalkWindowTreeSetupVisibleRegionTracking wwt(ETrue);
WalkWindowTree(wwt, EWalkChildren);
}
}
break;
}
case EWsWinOpDisableOnEvents:
{
TWindowServerEvent::RemoveFromSwitchOnEventList(*this);
if (iScreen->ChangeTracking())
{
TWalkWindowTreeSetupVisibleRegionTracking wwt(EFalse);
WalkWindowTree(wwt, EWalkChildren);
}
break;
}
case EWsWinOpEnableErrorMessages:
{
const TEventControl circumstances = *aCmd.EventControl;
TWindowServerEvent::AddToErrorMessageListL(*this, circumstances);
if (iScreen->ChangeTracking())
{
if(circumstances & EEventControlOnlyWhenVisible)
{
TWalkWindowTreeSetupVisibleRegionTracking wwt(ETrue);
WalkWindowTree(wwt, EWalkChildren);
}
}
break;
}
case EWsWinOpDisableErrorMessages:
{
TWindowServerEvent::RemoveFromErrorMessageList(*this);
if (iScreen->ChangeTracking())
{
TWalkWindowTreeSetupVisibleRegionTracking wwt(EFalse);
WalkWindowTree(wwt, EWalkChildren);
}
break;
}
case EWsWinOpEnableModifierChangedEvents:
{
const TInt modifierMask = aCmd.EnableModifierChangedEvents->modifierMask;
const TEventControl circumstances = aCmd.EnableModifierChangedEvents->circumstances;
TWindowServerEvent::AddToModifierChangedEventListL(*this, modifierMask, circumstances);
if (iScreen->ChangeTracking())
{
if(circumstances & EEventControlOnlyWhenVisible)
{
TWalkWindowTreeSetupVisibleRegionTracking wwt(ETrue);
WalkWindowTree(wwt, EWalkChildren);
}
}
break;
}
case EWsWinOpDisableModifierChangedEvents:
{
TWindowServerEvent::RemoveFromModifierChangedEventList(*this);
if (iScreen->ChangeTracking())
{
TWalkWindowTreeSetupVisibleRegionTracking wwt(EFalse);
WalkWindowTree(wwt, EWalkChildren);
}
break;
}
case EWsWinOpEnableGroupChangeEvents:
TWindowServerEvent::AddToGroupChangeEventListL(*this);
break;
case EWsWinOpDisableGroupChangeEvents:
TWindowServerEvent::RemoveFromGroupChangeEventEventList(*this);
break;
case EWsWinOpEnableFocusChangeEvents:
TWindowServerEvent::AddToFocusChangeEventListL(*this);
break;
case EWsWinOpDisableFocusChangeEvents:
TWindowServerEvent::RemoveFromFocusChangeEventEventList(*this);
break;
case EWsWinOpEnableGroupListChangeEvents:
TWindowServerEvent::AddToGroupListChangeEventListL(*this);
break;
case EWsWinOpDisableGroupListChangeEvents:
TWindowServerEvent::RemoveFromGroupListChangeEventEventList(*this);
break;
case EWsWinOpSetCustomPointerCursor:
CWsObject *pointercursor;
if ((pointercursor=iWsOwner->HandleToObj(*aCmd.Int, WS_HANDLE_POINTER_CURSOR))==NULL)
OwnerPanic(EWservPanicSprite);
SetPointerCursor((CWsPointerCursor *)pointercursor);
break;
case EWsWinOpSetPointerCursor:
SetPointerCursorByIndex(*aCmd.UInt);
break;
case EWsWinOpClearPointerCursor:
SetPointerCursor(NULL);
break;
case EWsWinOpSetNonFading:
{
WS_ASSERT_DEBUG(iScreen, EWsPanicNoScreen);
// No fading will occur from a graphical perspective, but the fade counts
// are maintained for BC reasons.
TWalkWindowTreeSetNonFading wwt(*aCmd.Bool);
WalkWindowTree(wwt,EWalkChildren);
}
break;
case EWsWinOpSetFade:
{
WS_ASSERT_DEBUG(iScreen, EWsPanicNoScreen);
TUint8 blackMap;
TUint8 whiteMap;
if (aCmd.SetFaded->UseDefaultMap())
{
iScreen->GetFadingParams(blackMap,whiteMap);
}
else
{
aCmd.SetFaded->GetFadingParams(blackMap,whiteMap);
}
if (aCmd.SetFaded->IncludeChildren())
{
TWalkWindowTreeSetFaded wwt(aCmd.SetFaded->Faded(),this,blackMap,whiteMap);
WalkWindowTree(wwt,EWalkChildren);
}
else
{
if (iWinType==EWinTypeGroup)
OwnerPanic(EWservPanicOpcode);
const TBool KNotifyObserver = ETrue; //yes please
const TBool KFaded = aCmd.SetFaded->Faded();
static_cast<CWsClientWindow*>(this)->SetFaded(KFaded, blackMap, whiteMap, KNotifyObserver);
}
}
break;
case EWsWinOpEnableAdvancedPointers:
User::LeaveIfError(IsActivated()?KErrInUse:KErrNone);
iBaseWinFlags |= EBaseWinAdvancedPointersEnabled;
break;
default:
return(EFalse);
}
return(ETrue);
}
/** @see MWsWindowTreeNode */
MWsWindowTreeNode::TType CWsWindowBase::NodeType() const
{
return static_cast<MWsWindowTreeNode::TType>(iWinType); //TWinType is a subset of MWsWindowTreeNode::TType
}
/** @see MWsWindowTreeNode */
const MWsWindow* CWsWindowBase::Window() const
{
return (iWinType!=EWinTypeGroup) ? (static_cast<const CWsWindow*>(this)) : NULL;
}
/** @see MWsWindowTreeNode */
const MWsSprite* CWsWindowBase::Sprite() const
{
return NULL;
}
/** @see MWsWindowTreeNode */
const MWsStandardTextCursor* CWsWindowBase::StandardTextCursor() const
{
return NULL;
}
/** @see MWsWindowTreeNode */
const MWsWindowGroup* CWsWindowBase::WindowGroup() const
{
return static_cast<MWsWindowGroup*>(WinGroup());
}
/** @see MWsWindowTreeNode */
const MWsWindowTreeNode* CWsWindowBase::ParentNode() const
{
return iParent;
}
TBool CWsWindowBase::QueueEvent(TInt aEvent, TInt aIntVal) const
{
if (WsOwner())
return(WsOwner()->EventQueue()->QueueEvent(iClientHandle, aEvent, aIntVal));
return(EFalse);
}
void CWsWindowBase::SetPointerCursorByIndex(TInt aIndex)
{
SetPointerCursor(CWsClient::SystemPointerCursor(aIndex));
}
void CWsWindowBase::SetPointerCursor(CWsPointerCursor *aCursor)
{
CWsPointerCursor *old=iPointerCursor;
iPointerCursor=aCursor;
if (iPointerCursor)
iPointerCursor->Open();
TWsPointer::UpdatePointerCursor();
if (old)
old->Close();
}
TBool CWsWindowBase::TreeIsObscured() const
{
TBool result;
TWalkWindowTreeIsObscured wwt(result);
CONST_CAST(CWsWindowBase *,this)->WalkWindowTree(wwt,EWalkChildren);
return(result);
}
CEventQueue *CWsWindowBase::EventQueue() const
{
CEventQueue* eventQueue = NULL;
if (iWsOwner)
eventQueue = iWsOwner->EventQueue();
return eventQueue;
}
TInt CWsWindowBase::Depth() const
{
TInt count=0;
const CWsWindowBase *win=this;
while (win->WinType()!=EWinTypeRoot)
{
++count;
win=win->iParent;
}
return(count);
}
void CWsWindowBase::WalkWindowTree(TWalkWindowTreeBase &aWalkClass,TWalkMode aMode)
//
// Walks windows in a front to back order
//
// If mode is EWalkBehind
// call DoIt for all windows that are behind 'this'
// else if mode is EWalkChildren
// call DoIt for all descendents
// else if mode is EWalkChildrenAndBehind
// call DoIt for for all descendents and windows behind
//
{
if (this!=NULL)
{
CWsWindowBase *win=this;
CWsWindowBase *end=RootWindow();
CWsWindowBase *sibling=win->iSibling;
CWsWindowBase *parent=win->iParent;
if (aMode!=EWalkBehind)
{
if (aMode==EWalkChildren)
end=win;
goto start;
}
do
{
if (sibling!=NULL)
{
win=sibling;
start: while(win->iChild!=NULL)
win=win->iChild;
}
else
win=parent;
sibling=win->iSibling; // De-reference win so it can be destroyed by 'DoIt'
parent=win->iParent;
if (win->iWinType!=EWinTypeGroup && aWalkClass.DoIt((CWsWindow *)win))
return;
} while(win!=end);
}
}
/* Walks windows in a front to back order
If aResume is EFalse the walk is identical to above.
Otherwise iWin is taken as the restart point, (any child windows will have been
walked previously).
*/
void CWsWindowBase::WalkWindowTree(TResumableWalkWindowTreeBase& aWalkClass, TWalkMode aMode, TBool aResume)
{
if (this != NULL)
{ // init
if (!aResume)
{
aWalkClass.iWin = this;
aWalkClass.iEnd = (aMode == EWalkChildren) ? this : RootWindow();
aWalkClass.iParent = aWalkClass.iWin->iParent;
if (aMode == EWalkBehind)
{
aWalkClass.iNextChild = aWalkClass.iWin->iSibling;
}
else
{ // ensure walk includes this and its child windows
aWalkClass.iNextChild = this;
}
}
else if (aWalkClass.iWin == aWalkClass.iEnd)
{
return; // walk had already reached end
}
do
{
if (aWalkClass.iNextChild != NULL)
{ // walk down tree to a leaf window
aWalkClass.iWin = aWalkClass.iNextChild;
while (aWalkClass.iWin->iChild != NULL)
{
aWalkClass.iWin = aWalkClass.iWin->iChild;
}
}
else
{ // walk up tree
aWalkClass.iWin = aWalkClass.iParent;
}
// De-reference iWin so it can be destroyed by 'DoIt'
aWalkClass.iNextChild = aWalkClass.iWin->iSibling;
aWalkClass.iParent = aWalkClass.iWin->iParent;
if ( ( aWalkClass.iWin->iWinType != EWinTypeGroup ) && aWalkClass.DoIt(static_cast<CWsWindow *>(aWalkClass.iWin)) )
{
return;
}
}
while (aWalkClass.iWin != aWalkClass.iEnd);
}
}
void CWsWindowBase::WalkWindowTreeBackToFront(TWalkWindowTreeBase &aWalkClass, TWalkModeBackToFront aMode)
{
// Walks windows in a back to front order
//
// If mode is EVisitParentNodesFirst
// call DoIt() on each node before walking their child windows.
if(iSibling)
iSibling->WalkWindowTreeBackToFront(aWalkClass,aMode);
if(aMode == EVisitParentNodesFirst)
aWalkClass.DoIt(static_cast<CWsWindow *>(this));
if(iChild)
iChild->WalkWindowTreeBackToFront(aWalkClass,aMode);
}
TBool CWsWindowBase::IsDSAHost() const
{
return EFalse;
}
TBool CWsWindowBase::IsActivated() const
{
return EFalse;
}
void CWsWindowBase::AddSprite(CWsSpriteBase * aSprite)
{
aSprite->SetNext(iSpriteList);
iSpriteList = aSprite;
}
void CWsWindowBase::RemoveSprite(CWsSpriteBase * aSprite)
{
if (aSprite == iSpriteList)
{
iSpriteList = aSprite->Next();
}
else
{
for (CWsSpriteBase * sprite = iSpriteList; sprite; sprite = sprite->Next())
{
if (sprite->Next() == aSprite)
{
sprite->SetNext(aSprite->Next());
}
}
}
aSprite->SetNext(0);
}
void CWsWindowBase::SendState(MWsWindowTreeObserver& aWindowTreeObserver) const
{
//Sprites
if(iSpriteList)
iSpriteList->SendState(aWindowTreeObserver);
}
#if defined(_DEBUG)
void CWsWindowBase::CheckTree()
{
TWalkWindowTreeCheck wwt1;
WalkWindowTree(wwt1,EWalkChildren);
}
enum {ENullWsHandle=0xFFFFFFFF}; // Events delivered to this handle are thrown away
TBool CWsWindowBase::IsClientHandleInUse(TUint32 aHandle)
{
if (aHandle==static_cast<TUint>(ENullWsHandle)) //This value has a special meaning in test code
return EFalse;
CWsObjectIx* index=iWsOwner->ObjectIndex();
const CWsObject* obj;
TInt length=index->Length();
TInt ii;
for (ii=0;ii<length;++ii)
{
obj=index->At(ii);
if (obj && (obj->Type()==WS_HANDLE_WINDOW || obj->Type()==WS_HANDLE_GROUP_WINDOW))
{
if (STATIC_CAST(const CWsWindowBase*,obj)->ClientHandle()==aHandle)
return ETrue;
}
}
return EFalse;
}
#endif