windowing/windowserver/nga/SERVER/openwfc/GROUPWIN.CPP
author William Roberts <williamr@symbian.org>
Thu, 03 Jun 2010 17:39:46 +0100
branchNewGraphicsArchitecture
changeset 87 0709f76d91e5
parent 0 5d03bc08d59c
child 116 171fae344dd4
permissions -rw-r--r--
Add MMP files to build libOpenVG_sw.lib which uses LINKAS to redirect to libOpenVG.dll (and the same for libEGL_sw.lib and libOpenVGU_sw.lib). Only the libEGL_sw.lib redirection isn't activated - this can't happen until there is a merged libEGL.dll which supports the OpenWF synchronisation and also implements the graphical support functions. The overall aim is to eliminate the *_sw.dll implementations, at least as a compile-time way of choosing a software-only implementation.The correct way to choose is to put the right set of libraries into a ROM with suitable renaming, and in the emulator to use the "switching DLL" technique to pick the right set. As the Symbian Foundation doesn't have any alternative implementations, we don't need the switching DLLs and we can build directly to the correct name.

// 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:
// Group window sub-class of CWsWindow
// 
//

#include <e32std.h>
#include "W32STD.H"
#include "W32CLICK.H"
#include "server.h"
#include "rootwin.h"
#include "windowgroup.h"
#include "walkwindowtree.h"
#include "wstop.h"
#include "EVENT.H"
#include "KEYCLICK.H"
#include "PRIKEY.H"
#include "panics.h"
#include "windowelementset.h"
#include "pointer.h"

GLREF_D TPtr nullDescriptor;
GLREF_D CDebugLogBase* wsDebugLog;

#if defined(_DEBUG)
TInt CWsWindowGroup::iSkipCount=0;
#endif

TBool CWsWindowGroup::iEventQueueTest=EFalse;			// For stress testing the EventQueue code

TInt CWsWindowGroup::iIdentifierCount=1;
TBool CWsWindowGroup::iFocusGainPreProcess=EFalse;		//'REMOVEFADINGONFOCUSGAIN' flag in INI file
RPointerArray< TDblQue<CWsWindowGroup> > CWsWindowGroup::iChains(3);
static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_SwEvent,ECapabilitySwEvent);
static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_WriteDeviceData,ECapabilityWriteDeviceData);
const TInt KArrayMaxGranularity=0x10000000;

CWsWindowGroup* CWsWindowGroup::NewL(CWsClient* aOwner, CScreen* aScreen, 
	const TWsClCmdCreateWindowGroup& aCmd)
	{
	CWsWindowGroup* self = new(ELeave) CWsWindowGroup(aOwner, aScreen);
	CleanupStack::PushL(self);
	self->ConstructL(aCmd);
	CleanupStack::Pop(self);
	return self;
	}

CWsWindowGroup::CWsWindowGroup(CWsClient* aOwner, CScreen* aScreen) : CWsWindowBase(aOwner,WS_HANDLE_GROUP_WINDOW,aScreen)
	{
	__DECLARE_NAME(_S("CWsWindowGroup"));
	iWinType=EWinTypeGroup;
	}

void CWsWindowGroup::PurgeCapturedKeys()
	{
	CWsObjectIx& objix=*WsOwner()->ObjectIndex();
	const TWsObject* ptr=objix.FirstObject();
	const TWsObject* end=ptr+objix.Length();
	while(++ptr<end)		//Fisrt one should always have a NULL object
		{
		const CWsObject* obj=ptr->iObject;
		if (obj 
			&& ((obj->Type()==WS_HANDLE_CAPTURE_KEY && STATIC_CAST(const CWsCaptureKey*,obj)->WindowGroup()==this)
				|| (obj->Type()==WS_HANDLE_CAPTURE_KEY_UPDOWNS && STATIC_CAST(const CWsCaptureKeyUpsAndDowns*,obj)->WindowGroup()==this)
				|| (obj->Type()==WS_HANDLE_CAPTURE_LONG_KEY && STATIC_CAST(const CWsCaptureLongKey*,obj)->WindowGroup()==this)))
			{
			objix.Remove(ptr);
			delete obj;
			}
		}
	objix.Tidy();
	CKeyboardRepeat::CancelRepeat(this);
	}

void CWsWindowGroup::SwitchToOwningWindow(CWsWindowGroup *aClosingWindow)
	{
	if (this==CWsTop::FocusWindowGroup())
		{
		CWsWindowGroup *winGroup=NULL;
//
// First try for an 'owning' window
//
		if (iOwningWindowGroup)
			{
			for(winGroup=RootWindow()->Child();winGroup;winGroup=winGroup->NextSibling())
				if (winGroup->Identifier()==iOwningWindowGroup && winGroup->iOrdinalPriority==iOrdinalPriority)
					goto gotIt;
			}
//
// If that failed look for the frontmost window belonging to the owner of dying window
//
		for(winGroup=RootWindow()->Child();winGroup;winGroup=winGroup->NextSibling())
			if (winGroup!=this && winGroup->WsOwner()==WsOwner() && winGroup->iOrdinalPriority==iOrdinalPriority)
				goto gotIt;
//
// Next try for the nominated default owning window group
//
		winGroup=iScreen->DefaultOwningWindowGroup();
		if (winGroup && winGroup->iOrdinalPriority==iOrdinalPriority)
			{
gotIt:		winGroup->SetOrdinalPosition(0,this);
			return;
			}
		}
	ResetFocus(aClosingWindow);
	}

CWsWindowGroup::~CWsWindowGroup()
	{
	MWsWindowTreeObserver* windowTreeObserver = NULL;
	if (Screen()&& iBaseWinFlags&EBaseWinNodeCreated)
		{
		windowTreeObserver = Screen()->WindowTreeObserver();
		if (windowTreeObserver)
			{
			if( iQueue && (iQueue->Last()!=this) )
				{
				//This node is part of chain, send notification unless this is the last node in the chain
				windowTreeObserver->WindowGroupChainBrokenAfter(*this);
				}
			windowTreeObserver->NodeReleased(*this);
			iBaseWinFlags &= ~EBaseWinNodeCreated;
			}
		}
	DisconnectFloatingSprites();
	
	if (wsDebugLog)
		{
		TLogMessageText buf;
		_LIT(KWSERVDebugLogGroupWindowId,"Destroying: RWindowGroup[0x%x,%d],Id=%d");
		buf.Format(KWSERVDebugLogGroupWindowId,iClientHandle,LogHandle(),iIdentifier);
		wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, buf);
		}
	if (CClick::IsHandler())
		CClick::OtherEvent(EEventGroupWindowClose,reinterpret_cast<TAny*>(iIdentifier));
	if (iQueue)
		{
		if (iQueue->Last()!=this)
			{		//Unlink all the children of the window that is being deleted
			TDblQueIter<CWsWindowGroup> iter(*iQueue);
			CWsWindowGroup* groupWin;
			iter.SetToLast();
			while ((groupWin=iter--)!=this)
				{
				WS_ASSERT_DEBUG(groupWin!=NULL && groupWin->iQueue==iQueue,EWsPanicGroupWindowChainError);
				if ( windowTreeObserver && (iQueue->Last()!=groupWin) )
					{
					//Send notification unless groupWin is the last node in the chain
					windowTreeObserver->WindowGroupChainBrokenAfter(*groupWin);
					}
				groupWin->iChainLink.Deque();
				// coverity[extend_simple_error]
				groupWin->iQueue=NULL;
				}
			}
		WS_ASSERT_DEBUG(iQueue->Last()==this,EWsPanicGroupWindowChainError);
		if(windowTreeObserver && !iQueue->IsEmpty())
			{
			//If there are chained nodes before this one, notify "chain broken" immediately before this node 
			TDblQueIter<CWsWindowGroup> iter(*iQueue);
			iter.SetToLast(); 	//i.e. set to this (see assert above)
			iter--;				//i.e. set to parent
			CWsWindowGroup* parent = iter;
			if(parent)
				{
				windowTreeObserver->WindowGroupChainBrokenAfter(*parent);
				}
			}
		TDblQueLinkBase* parentLink=iChainLink.iPrev;
		iChainLink.Deque();
		if (parentLink->iNext==parentLink->iPrev)		//Check to see chain no longer required
			{
			if (!iQueue->IsEmpty())
				{				//Only the parent is left in queue
				CWsWindowGroup* parent=iQueue->First();
				static_cast<TDblQueLink*>(parentLink)->Deque();
				WS_ASSERT_DEBUG(parent->iQueue==iQueue,EWsPanicGroupWindowChainError);
				// coverity[extend_simple_error]
				parent->iQueue=NULL;
				}
			DeleteQueue(iQueue);
			}
		}
	RemoveAllPriorityKeys();
	PurgeCapturedKeys();
	iTextCursor.Close();
	SetPointerCursor(NULL);
	for(CWsTopClientWindow *win=Child();win;win=win->NextSiblingTop())
		win->SetInactive();
	if (iScreen)
		{
		iScreen->RemoveFromDefaultOwningList(this);
		}
	CWsWindowBase::Shutdown();
	TWindowServerEvent::SendGroupChangedEvents();
	// coverity[extend_simple_error]
	iClientHandle=0;	// To block focus lost events being sent
// Decide which window to give focus to if WServ isn't shutting down
	if (iScreen && !CWsTop::ShuttingDown())
		SwitchToOwningWindow(this);
	delete iGroupName;
	delete iMessageArray;
	}

void CWsWindowGroup::DisconnectFloatingSprites()
	{
	CWsSpriteBase * current = iSpriteList;
	while (current)
		{
		CWsSpriteBase * next = current->Next();
		current->Deactivate();
		current->DisconnectGroupWin();
		current = next;
		}
	}

void CWsWindowGroup::DeleteQueue(TDblQue<CWsWindowGroup>* aQueue)
	{
	iChains.Remove(iChains.Find(aQueue));
	delete aQueue;
	if (iChains.Count()==0)
		{
		iChains.Compress();
		}
	}

void CWsWindowGroup::AdvanceIdentifierCount()
	{
	if (++iIdentifierCount>EMaxIdentifierCount)
		iIdentifierCount=1;		// so limit it to low value
	}

void CWsWindowGroup::ConstructL(const TWsClCmdCreateWindowGroup &aCmd)
	{
#if defined(_DEBUG)
	if (IsClientHandleInUse(aCmd.clientHandle))
		{
		OwnerPanic(EWservPanicDuplicateHandle);
		}
#endif
	NewObjL();
	iFlags=EGroupFlagAutoForeground|EGroupFlagMsgQueueNew;
	if (aCmd.focus)
		{
		iFlags|=EGroupFlagReceivesFocus;
		}
	iTextCursor.ConstructL(this);
	iClientHandle=aCmd.clientHandle;

	if(aCmd.screenDeviceHandle <= 0)
		{
		//Use primary screen. Client should make sure PrimaryScreenDevice is correct set up immediately after establishing session.
		iScreenDevice=iWsOwner->PrimaryScreenDevice();
		}
	else
		{
		//Use the specified screen
		iScreenDevice=STATIC_CAST(DWsScreenDevice*,iWsOwner->HandleToObj(aCmd.screenDeviceHandle,WS_HANDLE_SCREEN_DEVICE));
		}

	iScreen = (iScreenDevice) ? iScreenDevice->Screen() : CWsTop::Screen(); //if no screen device use screen 0

	CWsWindowGroup* parent=NULL;
	if (aCmd.parentId>0)
		{
		parent=CWsWindowGroup::WindowGroupFromIdentifier(aCmd.parentId);
		if (!parent)
			{
			OwnerPanic(EWservPanicWindow);
			}
		
 		if(parent->Screen() != iScreen)
 			{
 			OwnerPanic(EWservPanicWrongScreen);
 			}
		
		if (parent->iOrdinalPriorityAdjust>0)
			{
			WS_ASSERT_DEBUG(parent->iQueue==NULL,EWsPanicGroupWindowChainError);
			parent->iOrdinalPriorityAdjust=0;
			parent->UpdateOrdinalPriority(ETrue);
			}
		iOrdinalPriorityBase=parent->iOrdinalPriorityBase;
		iOrdinalPriority=iOrdinalPriorityBase;
		}

	do
		{
		AdvanceIdentifierCount();	// Always advance by at least one to stop re-using last id
		} while (WindowGroupFromIdentifier(iIdentifierCount)); // If current count is in use try again
	iIdentifier=iIdentifierCount;

	CWsWindowBase::ConstructL(RootWindow());
	iScreen->ResetFocus(NULL);
	
	if (parent)
		{
		TDblQue<CWsWindowGroup>* queue=parent->iQueue;
		if (queue && queue->Last()!=parent)
			User::Leave(KErrInUse);
		if (parent->iWsOwner!=iWsOwner)
			{
			_LIT_SECURITY_POLICY_S0(securityPolicy,parent->iChildSID);
			if (!securityPolicy().CheckPolicy(iWsOwner->ClientMessage()))
				User::Leave(KErrPermissionDenied);
			}
		if (!queue)
			{
			queue=new(ELeave) TDblQue<CWsWindowGroup>(_FOFF(CWsWindowGroup,iChainLink));
			CleanupStack::PushL(queue);
			User::LeaveIfError(iChains.Append(queue));
			CleanupStack::Pop(queue);
			queue->AddFirst(*parent);
			parent->iQueue=queue;			
			}
		iQueue=queue;		//Shouldn't set the queue until after it can leave
		iChainLink.Enque(&parent->iChainLink);
		
		MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();						
		if (windowTreeObserver)
			{
			windowTreeObserver->WindowGroupChained(*parent, *this);
			}			
		}
	iMessageArray=new(ELeave) CArrayVarSeg<TWsMessage>(1);
	if (CClick::IsHandler())
		{
		TGroupWindowOpenData params;
		params.iIdentifier=iIdentifier;
		params.iClient=iWsOwner->ConnectionHandle();
		params.iNumClientWindowGroups=NumClientWindowGroups()-1;	//Don't include this one
		CClick::OtherEvent(EEventGroupWindowOpen,&params);
		}
	if (wsDebugLog)
		{
		TLogMessageText buf;
		_LIT(KWSERVDebugLogGroupWindowId,"Creating: RWindowGroup[0x%x,%d],Id=%d");
		buf.Format(KWSERVDebugLogGroupWindowId,iClientHandle,LogHandle(),iIdentifier);
		wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything, buf);
		}
	}

void CWsWindowGroup::UpdateOrdinalPriority(TBool aDoAdjust)
	{
	TInt newPri;
	newPri=iOrdinalPriorityBase;
	if (iWsOwner==CWsTop::FocusWindowGroupOwner())
		newPri+=iOrdinalPriorityAdjust;
	CheckCapability(newPri);
	if (newPri!=iOrdinalPriority)
		{
		iOrdinalPriority=newPri;
		if (aDoAdjust)
			SetOrdinalPosition(0);
		}
	}

void CWsWindowGroup::SetOrdinalPriority(TInt aPos,TInt aPriority)
	{
	if (!iQueue)
		{
		iOrdinalPriorityBase=aPriority;
		UpdateOrdinalPriority(EFalse);
		}
	else
		{
		TDblQueIter<CWsWindowGroup> iter(*iQueue);
		CWsWindowGroup* group;
		while ((group=iter++)!=NULL)
			{
			group->iOrdinalPriorityBase=aPriority;
			group->iOrdinalPriority=aPriority;
			}
		}
	SetOrdinalPosition(aPos);
	}

void CWsWindowGroup::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();

	// For certain opcodes, check for the 'screen device deleted' condition. If it
	// has occured for the screen device associated with this group window then
	// those op-codes are not valid, and the client is panicked.
	switch (aOpcode)
		{
		case EWsWinOpEnableScreenChangeEvents:
		case EWsWinOpAllowChildWindowGroup:
		case EWsWinOpReceiveFocus:
		case EWsWinOpAutoForeground:
		case EWsWinOpSetOrdinalPositionPri:
		case EWsWinOpSetOrdinalPriorityAdjust:
		case EWsWinOpCaptureKey:
		case EWsWinOpCaptureKeyUpsAndDowns:
		case EWsWinOpCaptureLongKey:
		case EWsWinOpAddPriorityKey:
		case EWsWinOpSetTextCursor:
		case EWsWinOpSetTextCursorClipped:
		case EWsWinOpSetOwningWindowGroup:
		case EWsWinOpDefaultOwningWindow:
		case EWsWinOpSetName:
		case EWsWinOpDisableKeyClick:
		case EWsWinOpSendPointerEvent:
		case EWsWinOpSendAdvancedPointerEvent:
			{
			if (ScreenDeviceDeleted())
				OwnerPanic(EWservPanicGroupWinScreenDeviceDeleted);
			break;				
			};
		}
#endif

	TWsWinCmdUnion pData;
	pData.any=aCmdData;
	if (CWsWindowBase::CommandL(aOpcode,pData)==EFalse)
		{
		switch(aOpcode)
			{
			case EWsWinOpAllowChildWindowGroup:
				iChildSID=*pData.UInt;
				break;
			case EWsWinOpEnableScreenChangeEvents:
				SetScreenChangeEventStateL(ETrue);
				break;
			case EWsWinOpDisableScreenChangeEvents:
				SetScreenChangeEventStateL(EFalse);
				break;
			case EWsWinOpReceiveFocus:
				if (*pData.Bool!=(iFlags&EGroupFlagReceivesFocus))
					{
					iFlags&=~EGroupFlagReceivesFocus;
					if (*pData.Bool)
						iFlags|=EGroupFlagReceivesFocus;
					iScreen->ResetFocus(NULL);
					}
				break;
			case EWsWinOpAutoForeground:
				iFlags&=~EGroupFlagAutoForeground;
				if (*pData.Bool)
					iFlags|=EGroupFlagAutoForeground;
				break;
			case EWsWinOpSetOrdinalPositionPri:
			case EWsWinOpSetOrdinalPositionErr:
				{
				TInt priority=pData.OrdinalPos->ordinalPriority;
				TBool hascap = CheckCapability(priority);
				SetOrdinalPriority(pData.OrdinalPos->pos, priority);
				if (aOpcode == EWsWinOpSetOrdinalPositionErr)
					{
					SetReply(hascap?KErrNone:KErrPermissionDenied);
					}
				}
				break;
			case EWsWinOpSetOrdinalPriorityAdjust:
				if (!iQueue)
					{
					iOrdinalPriorityAdjust=*pData.Int;
					UpdateOrdinalPriority(ETrue);
					}
				break;
			case EWsWinOpCaptureKey:
				{
				if(!KSecurityPolicy_SwEvent().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::CaptureKey API")))
					{
					User::Leave(KErrPermissionDenied);
					}
				CWsCaptureKey *cKey=new(ELeave) CWsCaptureKey(this);
				CleanupStack::PushL(cKey);
				cKey->ConstructL(*pData.CaptureKey);
				CleanupStack::Pop();
				}
				break;
			case EWsWinOpCaptureKeyUpsAndDowns:
				{
				if(!KSecurityPolicy_SwEvent().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::CaptureKeyUpsAndDowns API")))
					{
					User::Leave(KErrPermissionDenied);
					}
				CWsCaptureKeyUpsAndDowns *cKey=new(ELeave) CWsCaptureKeyUpsAndDowns(this);
				CleanupStack::PushL(cKey);
				cKey->ConstructL(*pData.CaptureKey);
				CleanupStack::Pop();
				}
				break;
			case EWsWinOpCaptureLongKey:
				{
				if(!KSecurityPolicy_SwEvent().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::CaptureLongKey API")))
					{
					User::Leave(KErrPermissionDenied);
					}
				CWsCaptureLongKey *cKey=new(ELeave) CWsCaptureLongKey(this);
				CleanupStack::PushL(cKey);
				cKey->ConstructL(*pData.CaptureLongKey);
				CleanupStack::Pop();
				}
				break;
			case EWsWinOpCancelCaptureKey:
				if (*pData.UInt!=0)	// Ignore null handle
					{
					CWsObject *destroyObj = iWsOwner->HandleToObj(*pData.UInt, WS_HANDLE_CAPTURE_KEY);
					if (destroyObj)
						{
						//Cancel any repeat that is underway for this key
						const TWsWinCmdCaptureKey& capKey(*pData.CaptureKey);
						CKeyboardRepeat::CancelRepeat(this,capKey.key,EFalse,capKey.modifierMask);
						delete destroyObj;
						}
					else
						{
#ifdef _DEBUG
						// Attempt to cancel key capture with an incorrect handle
						OwnerPanic(EWservPanicDestroy);  
#endif // _DEBUG
						}					
					}
				break;
			case EWsWinOpCancelCaptureKeyUpsAndDowns:
				if (*pData.UInt!=0)	// Ignore null handle
					{
					CWsObject *destroyObj = iWsOwner->HandleToObj(*pData.UInt, WS_HANDLE_CAPTURE_KEY_UPDOWNS);
					if (destroyObj)
						{
						//Cancel any repeat that is underway for this key
						const TWsWinCmdCaptureKey& capKey(*pData.CaptureKey);
						CKeyboardRepeat::CancelRepeat(this,capKey.key,EFalse,capKey.modifierMask);
						delete destroyObj;
						}
					else
						{
#ifdef _DEBUG						
						// Attempt to cancel ups and downs key capture with an incorrect handle
						OwnerPanic(EWservPanicDestroy);
#endif // _DEBUG
						}					
					}
				break;
			case EWsWinOpCancelCaptureLongKey:
				if (*pData.UInt!=0)	// Ignore null handle
					{
					CWsObject *destroyObj = iWsOwner->HandleToObj(*pData.UInt, WS_HANDLE_CAPTURE_LONG_KEY);
					if (destroyObj)
						{
						//Cancel any repeat that is underway for this key
						const TWsWinCmdCaptureLongKey& capKey(*pData.CaptureLongKey);
						CKeyboardRepeat::CancelRepeat(this,capKey.inputKey,ETrue,capKey.modifierMask);
						delete destroyObj;
						} 
					else
						{
#ifdef _DEBUG						
						// Attempt to cancel long key capture with an incorrect handle
						OwnerPanic(EWservPanicDestroy);
#endif // _DEBUG
						}					
					}
				break;
			case EWsWinOpAddPriorityKey:
				AddPriorityKeyL(pData.PriorityKey->keycode, pData.PriorityKey->modifierMask, pData.PriorityKey->modifiers);
				break;
			case EWsWinOpRemovePriorityKey:
				RemovePriorityKey(pData.PriorityKey->keycode, pData.PriorityKey->modifierMask, pData.PriorityKey->modifiers);
				break;
			case EWsWinOpSetTextCursor:
				iTextCursor.SetL(*pData.SetTextCursor, EFalse);
				break;
			case EWsWinOpSetTextCursorClipped:
				iTextCursor.SetL(*pData.SetTextCursor, ETrue);
				break;
			case EWsWinOpCancelTextCursor:
				iTextCursor.Cancel();
				break;
			case EWsWinOpSetOwningWindowGroup:
				iOwningWindowGroup=*pData.Int;
				break;
			case EWsWinOpDefaultOwningWindow:
				{
				if(KSecurityPolicy_WriteDeviceData().CheckPolicy(iWsOwner->ClientMessage(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowGroup::DefaultOwningWindow API")))
					{
					iScreen->SetDefaultOwningWindow(this);
					}
				}
				break;
			case EWsWinOpName:
				iWsOwner->ReplyGroupName(iGroupName,*pData.Int);
				break;
			case EWsWinOpSetName:
				{
				HBufC *newName=NULL;
				const TInt size=*pData.Int;
				if (size>0)
					{
					newName=HBufC::NewLC(size);
					TPtr ptr(newName->Des());
					iWsOwner->RemoteReadL(ptr,0);
					CleanupStack::Pop(newName);
					}
				//Window Group Name is unchanged
				if (iGroupName && newName && *iGroupName == *newName)
					{
					delete newName;
					} 
				else  //Window Group Name is changed
					{  
					delete iGroupName;
					iGroupName=newName;
					TWindowServerEvent::SendGroupChangedEvents();
					if (iScreen && iScreen->ChangeTracking())
					    {
				        MWsWindowTreeObserver* const windowTreeObserver = iScreen->WindowTreeObserver();
				        if (windowTreeObserver)
				            windowTreeObserver->AttributeChanged(*this, MWsWindowTreeObserver::EWindowGroupName);
					    }
					}
				}
				break;
			case EWsWinOpIdentifier:
				SetReply(Identifier());
				break;
			case EWsWinOpDisableKeyClick:
				if (*pData.Bool)
					iFlags|=EGroupFlagDisableKeyClick;
				else
					iFlags&=~EGroupFlagDisableKeyClick;
				if (this==CWsTop::FocusWindowGroup())
					UpdateKeyClickState();
				break;
			case EWsWinOpSendAdvancedPointerEvent:
			case EWsWinOpSendPointerEvent:
				{
				TRawEvent eventCopy = *pData.RawEvent;
				if (TWsPointer::PreProcessClientEvent(eventCopy, aOpcode == EWsWinOpSendAdvancedPointerEvent))
					{
					if (!TWindowServerEvent::MousePress(eventCopy,this))
						{
						OwnerPanic(EWservPanicEventType);
						}
					}
				}
				break;
			case EWsWinOpClearChildGroup:
				if(iQueue)
					{
					TBool fBefore=EFalse; 
					TBool fAfter=EFalse; 
					// If there is nothing to clear, return KErrArgument
					if(iQueue->Last()==this)
						{
						SetReply(KErrArgument);
						break;
						}
					// fBefore is True if there is AT LEAST one window group queued before the current one
					else if(iQueue->First()!=this)
						{
						fBefore=ETrue;
						}
					// fAfter is True if there is MORE THAN one window group queued after the current one
					TDblQueIter<CWsWindowGroup> iter(*iQueue);
					iter.SetToLast();
					if(iter--!=this && iter!=this)
						{
						fAfter=ETrue;
						}
					TDblQue<CWsWindowGroup>* queue=NULL;
					// if fBefore and fAfter are True, create a new queue and copy all window groups after the current one into that queue
					if(fBefore && fAfter)
						{
						TInt ret=KErrNoMemory;
						queue=new TDblQue<CWsWindowGroup>(_FOFF(CWsWindowGroup,iChainLink));
						if(queue)
							{
							ret=iChains.Append(queue);	
							if(ret!=KErrNone)
								{
								delete queue;
								queue=NULL; 
								}
							}
						// Check that the queue creation and appending worked (we deque all the child groups even if it didn't) 
						if(ret!=KErrNone)
							{
							SetReply(ret);
							}
						}
					// If we've got zero or one window groups after, don't need to queue them
					if(!fAfter || fBefore)
						{
						iter.SetToLast();
						CWsWindowGroup* groupWin;
						while((groupWin=iter--)!=this)
							{
							groupWin->iChainLink.Deque();
							groupWin->iQueue=queue;
							if(queue)
								queue->AddFirst(*groupWin);
							}
						}
					// if we've got no window groups before, don't need to have a queue for this anymore
					if(!fBefore)
						{
						iChainLink.Deque();
						if (!fAfter)
							{
							DeleteQueue(iQueue);
							}
						iQueue=NULL;						
						}
					if (Screen())
						{
					MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();
					if (windowTreeObserver)
						{
						windowTreeObserver->WindowGroupChainBrokenAfter(*this);
							}
						}					
					}
				else // if this window group isn't queued, we can't clear any children
					{
					SetReply(KErrArgument);
					}
				break;
			case EWsWinOpSetChildGroup:
				{
				CWsWindowGroup* childWinGroup = CWsWindowGroup::WindowGroupFromIdentifier(*pData.Int);
				if(!childWinGroup																	//(no child to append)
					|| (iQueue && (!iQueue->IsLast(this) || (childWinGroup->iQueue==iQueue)))		//(GpWin has a child) || (GpWin and childGpWin in the same queue)
					|| (childWinGroup->iQueue && !childWinGroup->iQueue->IsFirst(childWinGroup))	//(childGpWin has a parent)
					|| (childWinGroup == this))														//(childGpWin == GpWin)
					{
					SetReply(KErrArgument);
					break;
					}
				if(iQueue)
				// If we have a chain, we're prepending ourselves to the child window group
				// So we take the childs chain and prepend each of the window groups in our own chain
				// beginning with the current window group and working backward
					{
					TDblQueIter<CWsWindowGroup> iter(*iQueue);
					iter.SetToLast();
					CWsWindowGroup* groupWin;
					if(childWinGroup->iQueue)
						{
						TDblQue<CWsWindowGroup>* oldQueue=iQueue;
						while((groupWin=iter--)!=NULL)
							{
							groupWin->iChainLink.Deque();
							childWinGroup->iQueue->AddFirst(*groupWin);
							groupWin->iQueue=childWinGroup->iQueue;
							}
						DeleteQueue(oldQueue);
						}
					else
						{
						iQueue->AddLast(*childWinGroup);
						childWinGroup->iQueue=iQueue;							
						}
					}
				else
				// 1. If we don't have a chain, and if the child has a chain, we can simply prepend this wg to the child
				// wg chain
				// 2. If we don't have a chain, and if the child does not have a chain, need to create a chain with the child
				//    as the owning member, and prepend our window group
					{
					if(childWinGroup->iQueue)
						{
						childWinGroup->iQueue->AddFirst(*this);
						iQueue=childWinGroup->iQueue;
						}
					else
						{
						TDblQue<CWsWindowGroup>* queue=new TDblQue<CWsWindowGroup>(_FOFF(CWsWindowGroup,iChainLink));
						TInt ret=KErrNoMemory;
						if (queue)
							{
							ret=iChains.Append(queue);
							if(ret!=KErrNone)
								{
								delete queue;
								}
							}
						if(ret!=KErrNone)
							{
							SetReply(ret);
							break;
							}
						queue->AddFirst(*childWinGroup);
						childWinGroup->iQueue=queue;
						queue->AddFirst(*this);
						iQueue=queue;						
						}						
					}
				if (Screen())
					{
				MWsWindowTreeObserver* const windowTreeObserver = Screen()->WindowTreeObserver();						
				if (windowTreeObserver)
					{
					windowTreeObserver->WindowGroupChained(*this, *childWinGroup);
						}
					}
				}
				break;
			default:						// All other window commands disallowed
				OwnerPanic(EWservPanicOpcode);
			}
		}
#if defined(_DEBUG)
	rootWindow->CheckTree();
#endif
	}
	
TPoint CWsWindowGroup::Origin() const
	{
	return TPoint(0,0);
	}
	
TRect CWsWindowGroup::AbsRect() const
	{
	return (TRect(RootWindow()->Abs().iTl,RootWindow()->Size()));
	}

TSize CWsWindowGroup::Size() const
	{
	return RootWindow()->Size();
	}

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

void CWsWindowGroup::SendStateWindowGroupChain(MWsWindowTreeObserver& aWindowTreeObserver) const
	{
	if ( iQueue && (!iQueue->IsEmpty()) && (iQueue->First()==this) )
		{
		TDblQueIter<CWsWindowGroup> iter(*iQueue);
		CWsWindowGroup* groupParent;
		CWsWindowGroup* groupChild;
		
		while ( (groupParent=iter++)!=NULL && (groupChild=iter)!=NULL )
			{
			aWindowTreeObserver.WindowGroupChained(*groupParent, *groupChild);
			}
		}
	}

TInt CWsWindowGroup::Identifier() const
	{
	return iIdentifier;
	}

TPtrC CWsWindowGroup::Name() const
	{
	return (iGroupName) ? *iGroupName : KNullDesC();
	}

TBool CWsWindowGroup::IsFocusable() const
	{
	return ReceivesFocus();
	}

TInt CWsWindowGroup::OrdinalPriority() const
	{
	return iOrdinalPriorityBase;
	}

const MWsClient * CWsWindowGroup::Client() const
    {
    return static_cast<const MWsClient*>(WsOwner());
    }


void CWsWindowGroup::UpdateKeyClickState()
	{
	CClick::SetKeyClickOveride(iFlags&EGroupFlagDisableKeyClick);
	}

void CWsWindowGroup::AreaCovered(TRegion &aRegion)
	{
	aRegion.Clear();
	for(CWsClientWindow *win=Child();win;win=win->NextSibling())
		aRegion.Union(*win->BaseArea());
	}

void CWsWindowGroup::SetOrdinalPosition(TInt aPos)
	{
	if (aPos==(TInt)KOrdinalPositionSwitchToOwningWindow)
		SwitchToOwningWindow(NULL);
	else
		SetOrdinalPosition(aPos,NULL);
	}

TBool CWsWindowGroup::SetOrdinalPosition(TInt aPos,CWsWindowGroup* aClosingWindow)
	{
	TBool ret=ETrue;
	if (!iQueue)
		ret=DoSetOrdinalPosition1(aPos,aClosingWindow);
	else
		{
		TDblQueIter<CWsWindowGroup> iter(*iQueue);
		CWsWindowGroup* group;
		iter.SetToLast();
		TInt after=0;
		TInt before=0;
		TInt* inc=&before;
		while ((group=iter--)!=NULL)
			{
			if (group==this)
				inc=&after;
			++(*inc);
			}
		TInt lastWinGpPos=NumWindowGroupsOnMyScreen(OrdinalPriority())-after;
		if (aPos<0)
			aPos=lastWinGpPos;
		else
			aPos=Min(aPos,lastWinGpPos);
		aPos-=before;
		aPos=Max(aPos,0);
		iter.SetToLast();
		CWsWindowGroup* firstForward=iter--;
		while (firstForward && firstForward->OrdinalPosition(EFalse)<aPos)
			{
			firstForward=iter--;
			++aPos;
			}
		if (!firstForward)
			iter.SetToFirst();
		else
			{
			iter.Set(*firstForward);
			MoveChainedWindows(iter,ETrue,aPos,aClosingWindow);
			iter.Set(*firstForward);
			iter++;
			}
		MoveChainedWindows(iter,EFalse,--aPos,aClosingWindow);
#if defined(_DEBUG)
		iter.SetToLast();
		TInt pos1=-1;
		TInt pos2;
		TBool ok=ETrue;
		while ((group=iter--)!=this)
			{
			pos2=group->OrdinalPosition(EFalse);
			if (pos2<=pos1)
				ok=EFalse;
			pos1=pos2;
			}
		WS_ASSERT_DEBUG(ok, EWsPanicGroupWindowChainError);
#endif
		}

	return ret;
	}


void CWsWindowGroup::MoveChainedWindows(TDblQueIter<CWsWindowGroup>& aIter,TBool aForward,TInt aPos,CWsWindowGroup* aClosingWindow)
	{
	CWsWindowGroup* groupWindow;
	while ((groupWindow=(aForward ? aIter-- : aIter++))!=NULL)
		{
		groupWindow->DoSetOrdinalPosition1(aPos,aClosingWindow);
		(aForward ? ++aPos : --aPos);
		}
	}

TBool CWsWindowGroup::DoSetOrdinalPosition1(TInt aPos,CWsWindowGroup* aClosingWindow)
	{
	TBool ret=EFalse;
	if (CheckOrdinalPositionChange(aPos))
		{
		if (Child())	// A group window with no children can not affect shadows
			{
			ret=ETrue;
			}
		DoSetOrdinalPosition2(aPos,aClosingWindow);
		}
	else if (aClosingWindow)    // do not reset focus if current groupwindow did not change its ordinal position
		iScreen->ResetFocus(aClosingWindow);
	return ret;
	}

void CWsWindowGroup::DoSetOrdinalPosition2(TInt aPos, CWsWindowGroup *aClosingWindow)
	{
	ChangeWindowPosition(aPos,iParent);
	ResetFocus(aClosingWindow);
	}

void CWsWindowGroup::LostFocus()
	{
	iTextCursor.LostFocus();
	iWsOwner->UpdateWindowOrdinalPrioritys();
	if (iClientHandle!=0)
		QueueEvent(EEventFocusLost);
	TWalkWindowTreeFocusChanged wwt(EFalse);
	WalkWindowTree(wwt,EWalkChildren);
	iWsOwner->SetClientPriority();
	}

void CWsWindowGroup::ReceivedFocus()
	{
	iWsOwner->UpdateWindowOrdinalPrioritys();
	iTextCursor.ReceivedFocus();
	// Used for event queue testing
	// Calling MoveToFront sets the queue of the focused window to first place, 
	// not doing so puts the queues in unusual situation thus stress testing the queue code. 
	// One such situation is where the focus queue is first but there is a gap before it (iEventPtr>iGlobalEventPtr)" 
#if defined(_DEBUG)
	if ((iEventQueueTest) && (++iSkipCount==5))
		{
		iSkipCount=0;
		}
	else
		{
		WsOwner()->EventQueue()->MoveToFront();
		}
#else
	WsOwner()->EventQueue()->MoveToFront();
#endif

	QueueEvent(EEventFocusGained);
	TWalkWindowTreeFocusChanged wwt(ETrue);
	WalkWindowTree(wwt,EWalkChildren);
	iWsOwner->SetClientPriority();
	UpdateKeyClickState();
	}

TInt CWsWindowGroup::NumWindowGroups(TBool aAllPriorities, TInt aPriority)
	{
	TInt count=0;
	TInt screenNo;
	for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo)
		{
		count+=CWsWindowGroup::NumWindowGroupsOnScreen(CWsTop::Screen(screenNo)->RootWindow()->Child(),aAllPriorities,aPriority);
		}
	return(count);
	}

TInt CWsWindowGroup::NumWindowGroupsOnScreen(const CWsWindowGroup* aGroupWin,TBool aAllPriorities,TInt aPriority)
	{
	TInt count=0;
	while (aGroupWin)
		{
		if (aAllPriorities || aGroupWin->iOrdinalPriority==aPriority)
			++count;
		aGroupWin=aGroupWin->NextSibling();
		}
	return count;
	}

inline TInt CWsWindowGroup::NumWindowGroupsOnMyScreen(TInt aPriority)
	{
	return(CWsWindowGroup::NumWindowGroupsOnScreen(Parent()->Child(),EFalse,aPriority));
	}

void CWsWindowGroup::GetFocusWindowGroupL(TInt aScreenNumber)
	{
	CWsWindowGroup *groupWin=(aScreenNumber==KDummyScreenNumber)?CWsTop::FocusWindowGroup():CWsTop::Screen(aScreenNumber)->FocusWindowGroup();	
	if (!groupWin)
		User::Leave(KErrGeneral);
	CWsClient::SetReply(groupWin->Identifier());
	}

TInt CWsWindowGroup::GetWindowGroupListL(TInt aScreenNo,TBool aAllPriorities,TInt aPriority,TInt aCount,CArrayFixFlat<TInt>* aList)
	{
	TInt count=aList->Count();
	CWsWindowGroup* groupWin=CWsTop::Screen(aScreenNo)->RootWindow()->Child();
	while(!aAllPriorities && groupWin && groupWin->iOrdinalPriority!=aPriority)
		groupWin=groupWin->NextSibling();
	while(groupWin && (aAllPriorities || groupWin->iOrdinalPriority==aPriority) && count<aCount)
		{
		aList->AppendL(groupWin->Identifier());
		++count;
		groupWin=groupWin->NextSibling();
		}
	return count;
	}
	
TInt CWsWindowGroup::SendWindowGroupListL(TInt aScreenNumber, TBool aAllPriorities, TInt aPriority, TInt aCount)
	{
	if ((aCount<1) || (aCount>(KArrayMaxGranularity/sizeof(TInt))))
		User::Leave(KErrArgument);
	CArrayFixFlat<TInt>* list=new(ELeave) CArrayFixFlat<TInt>(aCount);
	CleanupStack::PushL(list);
	TInt count(0);
	TInt requestedScreen=aScreenNumber;	
	if(requestedScreen==KDummyScreenNumber)
		{
		// get list from current focus screen first
		TInt focusScreenNo=CWsTop::CurrentFocusScreen()->ScreenNumber();
		count=GetWindowGroupListL(focusScreenNo, aAllPriorities, aPriority, aCount, list);
		if(count<aCount)
			{
			// now get from the remaining screen
			TInt screenNo;
			for(screenNo=0;screenNo<CWsTop::NumberOfScreens() && count<aCount;++screenNo)
				{
				// skip focus screen
				if (screenNo==focusScreenNo)
					continue;
				// count hold total number of window groups collected so far
				count=GetWindowGroupListL(screenNo, aAllPriorities, aPriority, aCount, list);
				}			
			}
		}
	else
		{
		count=GetWindowGroupListL(requestedScreen, aAllPriorities, aPriority, aCount, list);	
		}
	if (list->Count() > 0)	
		CWsClient::ReplyBuf(&list->At(0),count*sizeof(TInt));
	CleanupStack::PopAndDestroy(list);
	return(count);	// How many actually returned, may be less than asked for, but not more
	}

void CWsWindowGroup::GetWindowGroupListAndChainL(TInt aScreen,TBool aAllPriorities,TInt aPriority
																,RArray<RWsSession::TWindowGroupChainInfo>& list,TInt& aCountLeft)
	{
	CWsWindowGroup *groupWin=CWsTop::Screen(aScreen)->RootWindow()->Child();
	while(!aAllPriorities && groupWin && groupWin->iOrdinalPriority!=aPriority)
		groupWin=groupWin->NextSibling();
	while(groupWin && (aAllPriorities || groupWin->iOrdinalPriority==aPriority) && aCountLeft>0)
		{
		RWsSession::TWindowGroupChainInfo windowId;
		windowId.iId=groupWin->Identifier();
		if(!groupWin->IsChained(windowId.iParentId))
			windowId.iParentId=-1;	//Unchained window group
		list.AppendL(windowId);
		--aCountLeft;
		groupWin=groupWin->NextSibling();
		}
	}

TInt CWsWindowGroup::SendWindowGroupListAndChainL(TBool aAllPriorities, TInt aPriority, TInt aCount)
	{
	if ((aCount<1) || (aCount>(KArrayMaxGranularity/sizeof(RWsSession::TWindowGroupChainInfo))))
		User::Leave(KErrArgument);
	RArray<RWsSession::TWindowGroupChainInfo> list(aCount);
	CleanupClosePushL(list);
	TInt count=aCount;
	TInt focusScreenNo=CWsTop::CurrentFocusScreen()->ScreenNumber();
	GetWindowGroupListAndChainL(focusScreenNo,aAllPriorities,aPriority,list,count);
	TInt screenNo;
	for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo)
		{
		if (screenNo!=focusScreenNo)
			GetWindowGroupListAndChainL(screenNo,aAllPriorities,aPriority,list,count);
		}
	if (list.Count()>0)
		CWsClient::ReplyBuf(&list[0],aCount*sizeof(RWsSession::TWindowGroupChainInfo));
	CleanupStack::PopAndDestroy(&list);
	return(aCount-count);	// How many actually returned, may be less than asked for, but not more
	}

TBool CWsWindowGroup::SendEventToAllGroups(TBool aAllPriorities,TBool aOnePerClient,const TWsClCmdSendEventToWindowGroup& aData)
	{
	TWsEvent event=aData.event;
	if (event.Type()==EEventKey && event.Key()->iRepeats!=0)
		CKeyboardRepeat::CancelRepeat(NULL);		//Otherwise we will trip an invarient
	TInt priority=aData.parameter;
	TBool sentToAll=ETrue;
	TInt screenNo;
	for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo)
		{
		CWsWindowGroup *groupWin=CWsTop::Screen(screenNo)->RootWindow()->Child();
		if (!aAllPriorities)
			{
			while(groupWin && groupWin->iOrdinalPriority!=priority)
				groupWin=groupWin->NextSibling();
			}
		CWsWindowGroup* firstGroupWin=groupWin;
		CWsClient* lastOwner=NULL;
		CWsWindowGroup* groupWin2;
		while(groupWin && (aAllPriorities || groupWin->iOrdinalPriority==priority))
			{
			if (aOnePerClient)
				{
				if (lastOwner==groupWin->iWsOwner)
					goto ContinueLoop;
				lastOwner=groupWin->iWsOwner;
				for(groupWin2=firstGroupWin;groupWin2!=groupWin;groupWin2=groupWin2->NextSibling())
					{
					if (groupWin2->iWsOwner==groupWin->iWsOwner)
						break;
					}
				if (groupWin2->iWsOwner==groupWin->iWsOwner && groupWin2!=groupWin)
					goto ContinueLoop;
				}
			event.SetHandle(groupWin->ClientHandle());
			if (!groupWin->EventQueue()->QueueEvent(event))
				sentToAll=EFalse;
		ContinueLoop:
			groupWin=groupWin->NextSibling();
			}
		}
	return sentToAll;
	}

void CWsWindowGroup::ReleasePendedMessagesToAllGroups(CWsClient * aClient)
	{
	TInt screenNo;
	for (screenNo = 0; screenNo < CWsTop::NumberOfScreens(); ++screenNo)
		{
		CWsWindowGroup* groupWin = CWsTop::Screen(screenNo)->RootWindow()->Child();
		while (groupWin)
			{
			if (groupWin->WsOwner() == aClient)
				{
				groupWin->ReleasePendedMessage();
				}
			groupWin = groupWin->NextSibling();
			}
		}
	}

void CWsWindowGroup::ReleasePendedMessage()
    {
    if (iMessageArray->Count() > 0 && !(iFlags & EGroupFlagMessageSignalled))
        {
        if (!SignalMessageReady())
			{
			//The event queue is overflow
			// Cannot send a message notification event. 
			WsOwner()->WgMsgQueueOverflow(); // Set flag for client about having pended message(s)
			}
        }
    }

void CWsWindowGroup::SendMessageToAllGroupsL(CWsClient& aSender,TBool aAllPriorities,const TWsClCmdSendMessageToWindowGroup& aData)
	{
	TInt screenNo;
	for(screenNo=0;screenNo<CWsTop::NumberOfScreens();++screenNo)
		{
		CWsWindowGroup* groupWin=CWsTop::Screen(screenNo)->RootWindow()->Child();		
		if (!aAllPriorities)
			{
			while(groupWin && groupWin->iOrdinalPriority!=aData.identifierOrPriority)
				groupWin=groupWin->NextSibling();
			}
		while(groupWin && (aAllPriorities || (groupWin->iOrdinalPriority==aData.identifierOrPriority)))
			{
			groupWin->QueueMessageL(aData.uid, aData.dataLength, aSender);
			groupWin=groupWin->NextSibling();
			}
		}
	}

CWsWindowGroup *CWsWindowGroup::WindowGroupFromIdentifier(TInt aIdentifier)
	{
	// apply to all screens
	TInt screenNo;
	for (screenNo=0; screenNo<CWsTop::NumberOfScreens(); ++screenNo)
		{
		CWsWindowGroup* group;
		for(group=CWsTop::Screen(screenNo)->RootWindow()->Child(); group; group=group->NextSibling())
			{
			if (group->Identifier() == aIdentifier)
				return group;
			}
			
		}
		
	return NULL;
	}

CWsWindowGroup *CWsWindowGroup::WindowGroupFromIdentifierL(TInt aIdentifier)
	{
	CWsWindowGroup *group=WindowGroupFromIdentifier(aIdentifier);
	if (!group)
		User::Leave(KErrNotFound);
	return(group);
	}

CWsWindowGroup *CWsWindowGroup::FindWindowGroupL(CWsClient* aClient, TInt aIdentifier,TInt aOffset,const TPtrC *aMatch,const TThreadId *aThreadId)
	{
	CWsWindowGroup *group;
	if (aIdentifier)
		{
		group=WindowGroupFromIdentifier(aIdentifier);
		if (group)	// NULL group will cause KErrNotFound to be returned
			group=group->NextSibling();
		}
	else
		{
		// get window group for this session
		//
		group = aClient->Screen()->RootWindow()->Child();
		}

	for(;group;group=group->NextSibling())
		{
		if (aThreadId)
			{
			if (group->WsOwner()->Client().Id()==*aThreadId)
				break;	// Found one
			}
		else
			{
			const TDesC *groupName=&nullDescriptor;
			if (group->GroupName())
				groupName=group->GroupName();
			if (groupName->Length()>=aOffset && groupName->Mid(aOffset).MatchF(*aMatch)>=0)
				break;	// Found one
			}
		}
	if (!group)
		User::Leave(KErrNotFound);
	return(group);
	}

void CWsWindowGroup::AddPriorityKeyL(TUint aKeycode, TUint aModifierMask, TUint aModifiers)
	{
	iPriorityKeys=new(ELeave) TPriorityKey(aKeycode,aModifierMask,aModifiers,iPriorityKeys);
	}

void CWsWindowGroup::RemovePriorityKey(TUint aKeycode, TUint aModifierMask, TUint aModifiers)
	{
	for(TPriorityKey **ppk=&iPriorityKeys;*ppk;ppk=&((*ppk)->iNext))
		if ((*ppk)->Equals(aKeycode, aModifierMask, aModifiers))
			{
			TPriorityKey *next=(*ppk)->iNext;
			delete *ppk;
			*ppk=next;
			break;
			}
	}

void CWsWindowGroup::RemoveAllPriorityKeys()
	{
	TPriorityKey *pk=iPriorityKeys;
	while(pk)
		{
		TPriorityKey *next=pk->iNext;
		delete pk;
		pk=next;
		}
	}

TBool CWsWindowGroup::CheckForPriorityKey(const TKeyData &aKey, TInt aScanCode)
	{
	for(TPriorityKey *pk=iPriorityKeys;pk;pk=pk->iNext)
		{
		if (pk->KeyMatches(aKey))
			{	
			WsOwner()->PriorityKeyPressed(ClientHandle(),aKey, aScanCode);
			return(ETrue);
			}
		}
	return(EFalse);
	}

void CWsWindowGroup::StatusDump(TDes &aBuf)
	{
	_LIT(KWSERVStatusDumpWindowGroupInfo,"CWsWindowGroup[0x%x]RWindowGroup[0x%x,%d],Pri=%d,Id=%d,SizeMode=%d");
	aBuf.AppendFormat(KWSERVStatusDumpWindowGroupInfo,this,iClientHandle,LogHandle(),iOrdinalPriority,iIdentifier,iScreenDevice?iScreenDevice->AppMode():0);
	}

TBool CWsWindowGroup::SignalMessageReady()
	{
	TWsEvent event;
	event.SetType(EEventMessageReady);
	event.SetHandle(ClientHandle());
	event.SetTimeNow();
	SEventMessageReady& eventMessageReady=*(SEventMessageReady*)event.EventData();
	eventMessageReady.iWindowGroupIdentifier=Identifier();
	eventMessageReady.iMessageUid=(*iMessageArray)[0].iUid;
	eventMessageReady.iMessageParametersSize=iMessageArray->Length(0)-sizeof(TUid);
	TBool result = WsOwner()->EventQueue()->QueueEvent(event, EEventPriorityHigh);
	if (result)
		{
		iFlags |= EGroupFlagMessageSignalled;
		}
	return result;
	}

void CWsWindowGroup::QueueMessageL(TUid aUid, TInt aDataLength, CWsClient& aSender)
	{
	WS_ASSERT_DEBUG(iFlags&(EGroupFlagMsgQueueActive|EGroupFlagMsgQueueNew) || iMessageArray->Count()>=1,EWsPanicMsgQueueError);
	if (!(iFlags&(EGroupFlagMsgQueueActive|EGroupFlagMsgQueueNew)) && iMessageArray->Count()>=KMaxNumberOfMsgsInInactiveQueue)
		{
		WS_ASSERT_DEBUG(iMessageArray->Count()<=KMaxNumberOfMsgsInInactiveQueue,EWsPanicMsgQueueError);
		iMessageArray->Delete(1,iMessageArray->Count()-1);
		}
	TWsMessage* message=NULL;
	TRAPD(err,message=&iMessageArray->ExtendL(aDataLength+sizeof(aUid)));
	if ((err || (iFlags&EGroupFlagMsgQueueNew)) && iMessageArray->Count()>KMaxNumberOfMsgsInQueue)
		{
		iFlags&=~(EGroupFlagMsgQueueActive|EGroupFlagMsgQueueNew);
		iMessageArray->Delete(1,iMessageArray->Count()-(err?1:2));
		iMessageArray->Compress();
		}
	User::LeaveIfError(err);
	if (message)
		{
		message->iUid=aUid;
		TPtr8 ptr(&message->iTheRest[0],aDataLength);
		TRAP(err,aSender.RemoteReadL(ptr,0));
		if (err)
			{
			iMessageArray->Delete(iMessageArray->Count()-1);
			User::Leave(err);
			}
		if (!(iFlags & EGroupFlagMessageSignalled))
			{
			if (!SignalMessageReady())
				{
				//The event queue is overflow
				// Cannot send a message notification event. 
				WsOwner()->WgMsgQueueOverflow(); // Set flag for client about having pended message(s)
				}
			}
		}
	}

void CWsWindowGroup::FetchMessageL()
	{
	if (!(iFlags & EGroupFlagMessageSignalled))
		{
		OwnerPanic(EWservPanicFetchMessage);
		}
	CWsClient::ReplyBuf(&((*iMessageArray)[0].iTheRest[0]), (TInt) iMessageArray->Length(0) - sizeof(TUid));
	iMessageArray->Delete(0);
	iFlags |= EGroupFlagMsgQueueActive;
	iFlags &= ~(EGroupFlagMessageSignalled | EGroupFlagMsgQueueNew);
	if (iMessageArray->Count() > 0)
		{
		if (!SignalMessageReady())
			{
			//The event queue is overflow
			// Cannot send a message notification event. 
			WsOwner()->WgMsgQueueOverflow(); // Set flag for client about having pended message(s)
			}
		}
	}

TBool CWsWindowGroup::ScreenDeviceValid() const
	{
	return(iScreenDevice?iScreenDevice->ScreenDeviceValidState():(iScreen->ScreenSizeMode()==0));
	}

TBool CWsWindowGroup::CanReceiveFocus() const
	{
	return(ReceivesFocus() && iWsOwner->NotClosing() && (ScreenDeviceValid() || iFlags&EGroupFlagHandlesDeviceChange));
	}

void CWsWindowGroup::SetScreenChangeEventStateL(TBool aEnabled)
	{
	iFlags&=~EGroupFlagHandlesDeviceChange;
	if (aEnabled)
		{
		iFlags|=EGroupFlagHandlesDeviceChange;
		TWindowServerEvent::AddToScreenDeviceChangeEventListL(*this);
		if (iScreen->ScreenSizeMode()!=0)
			TWindowServerEvent::SendScreenDeviceChangedEvent(this);
		}
	else
		TWindowServerEvent::RemoveFromScreenDeviceChangeEventList(*this);
	iScreen->ResetFocus(NULL);
	}

void CWsWindowGroup::SetScreenDeviceValidState(const DWsScreenDevice *aDevice)
	{
	if (iScreenDevice==aDevice)
		{
		TBool state=ScreenDeviceValid();
		for(CWsTopClientWindow *win=Child();win;win=win->NextSiblingTop())
			{
			win->SetScreenDeviceValidState(state);
			}
		}
	}

void CWsWindowGroup::SetScreenDeviceValidStates(const DWsScreenDevice *aDevice)
	{
	for(CWsWindowGroup *groupWin=aDevice->RootWindow()->Child();groupWin;groupWin=groupWin->NextSibling())
		groupWin->SetScreenDeviceValidState(aDevice);
	}

void CWsWindowGroup::SetScreenDeviceValidStates(CScreen* aScreen)
	{
	CWsRootWindow* rootWindow = aScreen->RootWindow();

	CWsWindowGroup* groupWin;
	CWsTopClientWindow* win;
	for(groupWin=rootWindow->Child();groupWin;groupWin=groupWin->NextSibling())
		{
		TBool state=groupWin->ScreenDeviceValid();
		for(win=groupWin->Child();win;win=win->NextSiblingTop())
			{
			win->SetScreenDeviceValidStateFlag(state);
			win->ResetHiddenFlagsInParentAndChildren();
			}
		}
	}

void CWsWindowGroup::SetScreenDevice(DWsScreenDevice *aDevice)
	{
	iScreenDevice=aDevice;	
	}

void CWsWindowGroup::NewOrientation(TInt aMode,CFbsBitGc::TGraphicsOrientation aRotation, CWsRootWindow* aRootWindow)
	{
	for(CWsWindowGroup *groupWin=aRootWindow->Child();groupWin;groupWin=groupWin->NextSibling())
		{
		DWsScreenDevice *device=groupWin->Device();
		if (device)
			device->NewOrientation(aMode,aRotation);
		}
	}

void CWsWindowGroup::ResetFocus(CWsWindowGroup *aClosingWindow)
	{
	if (iScreen)
		{
		iScreen->ResetFocus(aClosingWindow);
		}
	}

TBool CWsWindowGroup::IsChained(TInt& aParentId)
	{
	if (!iQueue)
		return EFalse;
	if (iQueue->First()==this)
		aParentId=0;
	else
		aParentId=BeforeInChain()->Identifier();
	return ETrue;
	}

inline CWsWindowGroup* CWsWindowGroup::BeforeInChain()
	{		//You should only call this function if you know the window has a parent
	return reinterpret_cast<CWsWindowGroup*>(PtrSub(iChainLink.iPrev,_FOFF(CWsWindowGroup,iChainLink)));
	}

TBool CWsWindowGroup::CheckCapability(TInt& aOrdinalPriority)
	{
	if(aOrdinalPriority>=KPasswordWindowGroupPriority)
		{
		if(!KSecurityPolicy_SwEvent().CheckPolicy(WsOwner()->Client(),__PLATSEC_DIAGNOSTIC_STRING("Capability check failed")))
			{
			aOrdinalPriority=KPasswordWindowGroupPriority-1;
			return EFalse;
			}
		}
 	return ETrue;
	}
	
TBool CWsWindowGroup::HasVisibleTranslucentChild()
	{
	CWsWindowBase * child = iChild;
	while (child)
		{
		if (child->WinType() == EWinTypeClient)
			{
			CWsClientWindow * cliwin = static_cast<CWsClientWindow *>(child);
			if (cliwin->IsTranslucent() && cliwin->IsVisible())
				return ETrue;
			}
		else if (static_cast<CWsWindowGroup*>(child)->HasVisibleTranslucentChild())
			{
			return ETrue;
			}
		child = child->NextSibling();
		}
	return EFalse;
	}


TInt CWsWindowGroup::NumClientWindowGroups()
	{
	CWsObjectIx& objix=*WsOwner()->ObjectIndex();
	const TWsObject* ptr=objix.FirstObject();
	const TWsObject* end=ptr+objix.Length();
	TInt count=0;
	while(++ptr<end)		//First one should always have a NULL object
		{
		const CWsObject* obj=ptr->iObject;
		if (obj && obj->Type()==WS_HANDLE_GROUP_WINDOW)
			++count;
		}
	return count;
	}
	
void CWsWindowGroup::SetEventQueueTestState(TBool aEventQueState)
	{
	iEventQueueTest = aEventQueState;
	}