windowing/windowserver/nonnga/SERVER/GROUPWIN.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/GROUPWIN.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1418 @@
+// 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"
+
+GLREF_D TPtr nullDescriptor;
+GLREF_D CDebugLogBase* wsDebugLog;
+
+#if defined(_DEBUG)
+TInt CWsWindowGroup::iSkipCount=0;
+#endif
+
+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()
+	{
+	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);
+				groupWin->iChainLink.Deque();
+				groupWin->iQueue=NULL;
+				}
+			}
+		WS_ASSERT_DEBUG(iQueue->Last()==this,EWsPanicGroupWindowChainError);
+		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);
+				parent->iQueue=NULL;
+				}
+			DeleteQueue(iQueue);
+			}
+		iQueue=NULL;
+		}
+	RemoveAllPriorityKeys();
+	PurgeCapturedKeys();
+	iTextCursor.Close();
+	SetPointerCursor(NULL);
+	for(CWsClientWindow *win=Child();win;win=win->NextSibling())
+		win->SetInactive();
+	if (iScreen)
+		{
+		iScreen->RemoveFromDefaultOwningList(this);
+		}
+	CWsWindowBase::Shutdown();
+	TWindowServerEvent::SendGroupChangedEvents();
+	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::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;
+		}
+	
+	CWsWindowBase::ConstructL(RootWindow());
+	
+	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);
+		}
+	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;
+	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:
+			{
+			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:
+				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();
+					}
+				}
+				break;
+			case EWsWinOpIdentifier:
+				SetReply(Identifier());
+				break;
+			case EWsWinOpDisableKeyClick:
+				if (*pData.Bool)
+					iFlags|=EGroupFlagDisableKeyClick;
+				else
+					iFlags&=~EGroupFlagDisableKeyClick;
+				if (this==CWsTop::FocusWindowGroup())
+					UpdateKeyClickState();
+				break;
+			case EWsWinOpSendPointerEvent:
+				if (!TWindowServerEvent::MousePress(*pData.RawEvent,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;
+						}
+					}
+				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;
+						}						
+					}
+				}
+				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::UpdateKeyClickState()
+	{
+	CClick::SetKeyClickOveride(iFlags&EGroupFlagDisableKeyClick);
+	}
+
+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
+		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 (++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::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);
+	}
+
+void 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);
+	if(WsOwner()->EventQueue()->QueueEvent(event,EEventPriorityHigh))
+		{
+		iFlags|=EGroupFlagMessageSignalled;
+		}
+	}
+
+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))
+			{
+			WS_ASSERT_DEBUG(iMessageArray->Count()==1,EWsPanicMsgQueueError);
+			SignalMessageReady();
+			}
+		}
+	}
+
+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)
+		{
+		SignalMessageReady();
+		}
+	}
+
+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(CWsClientWindow *win=Child();win;win=win->NextSibling())
+			{
+			win->SetScreenDeviceValidState(state);
+			}
+		}
+	}
+
+void CWsWindowGroup::SetScreenDeviceValidStates(const DWsScreenDevice *aDevice)
+	{
+	for(CWsWindowGroup *groupWin=aDevice->RootWindow()->Child();groupWin;groupWin=groupWin->NextSibling())
+		groupWin->SetScreenDeviceValidState(aDevice);
+	}
+
+TBool CWsWindowGroup::SetScreenDeviceValidStates(const TBool aScreenSizeChanged,const TBool aSwapWidthAndHeight, CScreen* aScreen)
+	{
+	TBool ret=EFalse;
+	CWsRootWindow* rootWindow = aScreen->RootWindow();
+
+	CWsWindowGroup* groupWin;
+	CWsClientWindow* win;
+	for(groupWin=rootWindow->Child();groupWin;groupWin=groupWin->NextSibling())
+		{
+		TBool state=groupWin->ScreenDeviceValid();
+		for(win=groupWin->Child();win;win=win->NextSibling())
+			{
+			win->SetScreenDeviceValidStateFlag(state);
+			win->ResetHiddenFlagsInParentAndChildren();
+			}
+		}
+	if (aScreenSizeChanged)
+		{
+		rootWindow->ScreenSizeChanged(aSwapWidthAndHeight);
+		}
+
+	aScreen->AddRedrawRegion(rootWindow->WindowArea());
+
+	return ret;
+	}
+
+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;
+	}
+