// 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"
CWsWindowBase::CWsWindowBase(CWsClient* aOwner,WH_HANDLES aType, CScreen* aScreen) : CWsScreenObject(aOwner,aType,aScreen)
{
}
void CWsWindowBase::ConstructL(CWsWindowBase *parent)
{
iParent=parent;
iSibling=parent->iChild;
parent->iChild=this;
SetOrdinalPosition(0);
iFadeCount = iParent->iFadeCount;
}
CWsWindowBase *CWsWindowBase::GetPrevSibling() const
{
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);
}
// Andy - this is a kind of "next cousin" function
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;
}
}
/* This const casts in this function are horrible and need revisiting. */
CWsWindowGroup *CWsWindowBase::WinGroup() const
{
switch (iWinType)
{
case EWinTypeClient:
{
if (iParent)
{
CWsWindowBase* win = const_cast<CWsWindowBase*>(this);
while(win->WinType()!=EWinTypeGroup)
win=win->BaseParent();
return static_cast<CWsWindowGroup*>(win);
}
return 0;
}
case EWinTypeGroup:
return const_cast<CWsWindowGroup*>(static_cast<const CWsWindowGroup*>(this));
default:
return 0;
}
}
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.
//
{
if (!iParent)
{
OwnerPanic(EWservPanicParentDeleted);
}
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)
{
if (aNewParent != iParent)
{
iScreen->ScheduleRegionUpdate(NULL);
TWalkWindowTreeScheduleRedraws wwt;
WalkWindowTree(wwt, EWalkChildren);
}
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;
}
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:
if (!WinGroup())
{
OwnerPanic(EWservPanicParentDeleted);
}
SetReply(WinGroup()->Identifier());
break;
case EWsWinOpEnableOnEvents:
TWindowServerEvent::AddToSwitchOnEventListL(*this, *aCmd.EventControl);
break;
case EWsWinOpDisableOnEvents:
TWindowServerEvent::RemoveFromSwitchOnEventList(*this);
break;
case EWsWinOpEnableErrorMessages:
TWindowServerEvent::AddToErrorMessageListL(*this, *aCmd.EventControl);
break;
case EWsWinOpDisableErrorMessages:
TWindowServerEvent::RemoveFromErrorMessageList(*this);
break;
case EWsWinOpEnableModifierChangedEvents:
TWindowServerEvent::AddToModifierChangedEventListL(*this, aCmd.EnableModifierChangedEvents->modifierMask,
aCmd.EnableModifierChangedEvents->circumstances);
break;
case EWsWinOpDisableModifierChangedEvents:
TWindowServerEvent::RemoveFromModifierChangedEventList(*this);
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);
Screen()->AcceptFadeRequest( reinterpret_cast<CWsWindow*>(this),
ETrue,
EFalse,
ETrue );
}
break;
case EWsWinOpSetFade:
{
if (!iParent)
{
OwnerPanic(EWservPanicParentDeleted);
}
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);
static_cast<CWsClientWindow*>(this)->SetFaded(aCmd.SetFaded->Faded(),blackMap,whiteMap);
}
if (CWsTop::IsFadeEnabled())
{
Screen()->AcceptFadeRequest( reinterpret_cast<CWsWindow *> (this),
aCmd.SetFaded->Faded(),
EFalse,
aCmd.SetFaded->IncludeChildren() );
}
}
break;
default:
return(EFalse);
}
return(ETrue);
}
TBool CWsWindowBase::QueueEvent(TInt aEvent) const
{
if (WsOwner())
return(WsOwner()->EventQueue()->QueueEvent(iClientHandle, aEvent));
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();
WsPointer::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
{
return(iWsOwner->EventQueue());
}
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);
}
}
#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
TBool CWsWindowBase::IsDSAHost() const
{
return EFalse;
}