windowing/windowserver/nonnga/SERVER/WINBASE.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/WINBASE.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,626 @@
+// 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;
+	}
+