// Copyright (c) 1994-2010 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:
// Top level window server code
// 
//

#include "EVENT.H"

#include "W32STD.H"
#include <hal.h>
#include <w32adll.h>
#include "W32CLICK.H"
#include "server.h"
#include "windowgroup.h"
#include "KEYCLICK.H"
#include "wstop.h"
#include "panics.h"
#include "screen.h"
#include "inifile.h"
#include "password.h"
#include "pointer.h"
#include "debugbar.h"
#include "advancedpointereventhelper.h"
#include "Graphics/wsgraphicdrawerinternal.h"

GLREF_D CDebugLogBase *wsDebugLog;

GLREF_C void StateDump();
GLREF_C void HeapDump();

#define IMPOSSIBLE 0xFFFFFFFF

const TWsWinCmdCaptureKey ImpossibleKeyPress=
	{
	IMPOSSIBLE,	// Impossible to hit key combination, used for disabling Hot Keys
	IMPOSSIBLE,
	IMPOSSIBLE};

const TWsWinCmdCaptureKey DefaultHotKeys[TWindowServerEvent::ENumHotKeys]={
	{	// Enable logging
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	5}, // E
	{	// Disable logging
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	4}, // D
	{	// Window server internal dump to log
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	23},// W
	{	// The key of death
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	11},// K
	{	// Shutdown window server
#if defined(_DEBUG)
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	24},// X
#else
	IMPOSSIBLE,	// Impossible to hit key combination, effectively disables shutdown key in release builds
	IMPOSSIBLE,
	IMPOSSIBLE},
#endif
	{	// Heap dump
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	8}, // H
	{	// Inc Contrast
	0,
	0,
	EKeyIncContrast},
	{	// Dec Contrast
	0,
	0,
	EKeyDecContrast},
	{	// Off
	0,
	0,
	EKeyOff},
	{	// Backlight on 
	0,
	0,
	EKeyBacklightOn},
	{	// Backlight off
	0,
	0,
	EKeyBacklightOff},
	{	// Backlight toggle
	0,
	0,
	EKeyBacklightToggle},
	{	// Screen Dimension Change
	0,
	0,
	EKeyScreenDimension0},
	{
	0,
	0,
	EKeyScreenDimension1},
	{
	0,
	0,
	EKeyScreenDimension2},
	{
	0,
	0,
	EKeyScreenDimension3},
#if defined(_DEBUG)
	{	// Display mode cycle
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	21},// U
	{	// Orientation cycle
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	15},// O
#else
	{	// Display mode cycle
	IMPOSSIBLE,	// Impossible to hit key combination
	IMPOSSIBLE,
	IMPOSSIBLE},
	{	// Orientation cycle
	IMPOSSIBLE,	// Impossible to hit key combination
	IMPOSSIBLE,
	IMPOSSIBLE},
#endif
	{	// Inc Brightness
	0,
	0,
	EKeyIncBrightness},
	{	// Dec Brightness
	0,
	0,
	EKeyDecBrightness},
	{	// Cycle focus screen
	EModifierFunc|EModifierCtrl|EModifierShift,
	EModifierFunc|EModifierCtrl|EModifierShift,
	9}, // I
	};

CKeyTranslator *TWindowServerEvent::iKeyTranslator=NULL;
TEventRequestQueue TWindowServerEvent::iSwitchOnQueue;
TEventRequestQueue TWindowServerEvent::iErrorMessageQueue;
TEventRequestQueue TWindowServerEvent::iModifierChangedQueue;
TEventRequestQueue TWindowServerEvent::iGroupChangedQueue;
TEventRequestQueue TWindowServerEvent::iFocusChangedQueue;
TEventRequestQueue TWindowServerEvent::iGroupListChangedQueue;
TEventRequestQueue TWindowServerEvent::iScreenDeviceChangedQueue;
TTime TWindowServerEvent::iPrevOomMessageTime;
CCaptureKeys *TWindowServerEvent::iCaptureKeys;
CWsHotKey *TWindowServerEvent::iHotKeys;
TInt TWindowServerEvent::iModifierState;
CRawEventReceiver *TWindowServerEvent::iEventReceiver;
RArray<TWindowServerEvent::TRawEventHandler> TWindowServerEvent::iEventHandlers;
CArrayFixFlat<SNotificationHandler> *TWindowServerEvent::iNotificationHandlers;
TInt TWindowServerEvent::iPotentialEventHandlers=0;
TUint32 TWindowServerEvent::iBinaryFlags=0x00;
RArray<TDrawerHandler>* TWindowServerEvent::iDrawerHandlers;
RArray<TWsEventHandler> TWindowServerEvent::iWsEventHandlers;
TInt TWindowServerEvent::iEventHandlerCount=0;
TRepeatKey CKeyboardRepeat::iCurrentRepeat;
TRepeatKey CKeyboardRepeat::iAlternateRepeat;
TInt CKeyboardRepeat::iRepeatRollover=1;
CKeyboardRepeat::TRepeatType CKeyboardRepeat::iRepeating=ERepeatNone;
CKeyboardRepeat *CKeyboardRepeat::iThis=NULL;
TTimeIntervalMicroSeconds32 CKeyboardRepeat::iInitialTime;
TTimeIntervalMicroSeconds32 CKeyboardRepeat::iTime;
CWsWindowGroup *CKeyboardRepeat::iFocus=NULL;
TBool CKeyboardRepeat::iAlternateRepeatExists=EFalse;
CWsCaptureLongKey* CKeyboardRepeat::iLongCapture=NULL;


void TWindowServerEvent::DeleteHotKeys()
	{
	CWsHotKey *hotKey=iHotKeys;
	while(hotKey)
		{
		CWsHotKey *next=hotKey->iNext;
		delete hotKey;
		hotKey=next;
		}
	iHotKeys=NULL;
	}

void TWindowServerEvent::DeleteStatics()
	{
	DeleteHotKeys();
	delete iCaptureKeys;
	CKeyboardRepeat::Destroy();
	delete iKeyTranslator;
	delete iEventReceiver;
	iEventHandlers.Close();
	delete iNotificationHandlers;
	iDrawerHandlers->Close();
	delete iDrawerHandlers;
	iWsEventHandlers.Close();
	}

void TWindowServerEvent::InitStaticsL()
//
// Create the CEvent active object.
//
	{
#if defined(__WINS__)
	WS_ASSERT_DEBUG(TWindowServerEvent::ENumHotKeys==EHotKeyLastKeyType+1, EWsPanicUnknownCaptureKey);
#endif
	iEventReceiver=new(ELeave) CRawEventReceiver(EEventPriority);
	iEventReceiver->ConstructL();
	iKeyTranslator=CKeyTranslator::New();
	User::LeaveIfNull(iKeyTranslator);
    
//  Change keyboard mapping according to information the HAL
	TInt keyboardIndex;
	if (HAL::Get(HALData::EKeyboardIndex,keyboardIndex)==KErrNone)
		{
		_LIT(KLitKeyDataDllName,"EKDATA.%02d");
		TBuf<16> keyDataDllName;
		keyDataDllName.Format(KLitKeyDataDllName,keyboardIndex);
		iKeyTranslator->ChangeKeyData(keyDataDllName);
		}

	iCaptureKeys=new(ELeave) CCaptureKeys;
	iCaptureKeys->Construct();
	for (TInt index=0;index<TWindowServerEvent::ENumHotKeys;index++)
		ConstructDefaultHotKeyL(index,DefaultHotKeys[index]);
	CKeyboardRepeat::NewL();
	CKeyboardRepeat::SetRepeatTime(EDefaultInitialRepeatTime, EDefaultRepeatTime);
	iEventHandlers=RArray<TRawEventHandler>(2);
	iNotificationHandlers=new(ELeave) CArrayFixFlat<SNotificationHandler>(2);
	iDrawerHandlers = new(ELeave) RArray<TDrawerHandler>(4);
	}

void TWindowServerEvent::LinkHotKey(CWsHotKey *aWsHotKey)
	{
	aWsHotKey->SetLink(iHotKeys);
	iHotKeys=aWsHotKey;
	}

void TWindowServerEvent::ConstructDefaultHotKeyL(TInt aHotKey, const TWsWinCmdCaptureKey &aSystemKey)
	{
	CWsHotKey* hotKey=new(ELeave) CWsHotKey(aHotKey, ETrue);
	// hotKey is pushed onto the cleanup stack in method ConstructLD.
	hotKey->ConstructLD(aSystemKey);
	LinkHotKey(hotKey);
	}

CWsHotKey* TWindowServerEvent::ClearHotKeysL(TInt aHotKey)
	{
	if (aHotKey>ENumHotKeys)
		{
		User::Leave(KErrArgument);
		}
	CWsHotKey** pHotKey= &iHotKeys;
	CWsHotKey* defaultHotKey=NULL;
	while(*pHotKey)
		{
		TBool unlinked=EFalse;
		if ((*pHotKey)->HotKeyType()==aHotKey)
			{
			CWsHotKey *free=*pHotKey;
			if (free->IsDefault())
				{
				free->SetL(ImpossibleKeyPress);
				defaultHotKey=free;
				}
			else
				{
				*pHotKey=(*pHotKey)->iNext;
				delete free;
				unlinked=ETrue;
				}
			}
		if (!unlinked)
			{
			pHotKey=&(*pHotKey)->iNext;
			}
		}
	return(defaultHotKey);
	}

void TWindowServerEvent::ResetDefaultHotKeyL(TInt aHotKey)
	{
	if ((aHotKey<0) || (aHotKey>=ENumHotKeys))
		{
		User::Leave(KErrArgument);
		}
	CWsHotKey* defaultHotKey=ClearHotKeysL(aHotKey);
	WS_ASSERT_DEBUG(defaultHotKey, EWsPanicDefaultHotKeyNotFound);
	defaultHotKey->SetL(DefaultHotKeys[aHotKey]);
	}

void TWindowServerEvent::SetHotKeyL(const TWsClCmdSetHotKey &aHotKey)
	{
	if (aHotKey.type>ENumHotKeys)
		User::Leave(KErrArgument);
//
	CWsHotKey *hotKey=new(ELeave) CWsHotKey(aHotKey.type, EFalse);
//
	TWsWinCmdCaptureKey captureKey;
	captureKey.modifiers=aHotKey.modifiers;
	captureKey.modifierMask=aHotKey.modifierMask;
	captureKey.key=aHotKey.keycode;
	hotKey->ConstructLD(captureKey);
//
	LinkHotKey(hotKey);
	}

void TWindowServerEvent::AddEventHandler(MEventHandler *aEventHandler, TBool aAdvancedPointersEnabled)
	{
#if defined(_DEBUG)
	TRAPD(err,iEventHandlers.AppendL(TRawEventHandler(aEventHandler, aAdvancedPointersEnabled)));
	WS_ASSERT_DEBUG(err==KErrNone, EWsPanicEventHandlerInconsistency);
#else
	iEventHandlers.AppendL(TRawEventHandler(aEventHandler, aAdvancedPointersEnabled));	//Shouldn't leave
#endif
	}

void TWindowServerEvent::RemoveEventHandler(const MEventHandler *aEventHandler)
	{
	TInt count=iEventHandlers.Count();
	TInt ii;
	for(ii=0;ii<count;++ii)
		{
		if (iEventHandlers[ii].iEventHandler==aEventHandler)
			{
			if (iEventHandlerCount>0)  
				{
				iBinaryFlags |= ERemovedEventHandlerWhileProcessingRawEvents;
				iEventHandlers[ii].iEventHandler=NULL; // replace the Handler with null to keep size of the array
				}
			else 
				{
				iEventHandlers.Remove(ii);
				}
			return;
			}
		}
	}

void TWindowServerEvent::PotentialEventHandlerL(TInt aNum)
	{
	iPotentialEventHandlers+=aNum;
	WS_ASSERT_DEBUG(iPotentialEventHandlers>=iEventHandlers.Count(), EWsPanicEventHandlerInconsistency);
	TRAPD(err,iEventHandlers.Reserve(iPotentialEventHandlers));
	if (err!=KErrNone)
		{
		if (aNum>0)
			User::Leave(err);
		}
	else if (iPotentialEventHandlers==0)
		iEventHandlers.Compress();
	}

void SendSwitchOnEvent(TEventRequestItem *aQptr, TInt aEvent, TInt )
	{
	aQptr->iWindow->QueueEvent(aEvent);
	}

/*void SendSwitchOffEvent(TEventRequestItem *aQptr, TInt , TInt )
	{
	aQptr->iWindow->QueueEvent(EEventSwitchOff);
	}*/

void SendErrorMessage(TEventRequestItem *aQptr, TInt aCategory, TInt aError)
	{
	TWsEvent event;
	event.SetType(EEventErrorMessage);
	event.SetHandle(aQptr->iWindow->ClientHandle());
	event.ErrorMessage()->iErrorCategory=(TWsErrorMessage::TErrorCategory)aCategory;
	event.ErrorMessage()->iError=aError;
	event.SetTimeNow();
	aQptr->iWindow->EventQueue()->QueueEvent(event,EEventPriorityHigh);
	}

void SendModifierChangedEvent(TEventRequestItem *aQptr, TInt aChanged, TInt )
	{
	TInt tmpChanged=aChanged&aQptr->iParam;
	if (tmpChanged)
		{
		TWsEvent event;
		event.SetType(EEventModifiersChanged);
		event.SetHandle(aQptr->iWindow->ClientHandle());
		event.ModifiersChanged()->iChangedModifiers=tmpChanged;
		event.ModifiersChanged()->iModifiers=TWindowServerEvent::GetStoredModifierState();
		event.SetTimeNow();
		aQptr->iWindow->EventQueue()->QueueEvent(event,EEventPriorityHigh);
		}
	}

void TWindowServerEvent::ProcessEventQueue(TEventRequestQueue &aQueue, TSendEventFunc aFunc, TInt aParam1, TInt aParam2)
	{
	TSglQueIter<TEventRequestItem> iter(aQueue.Queue());
	TEventRequestItem *qPtr;
	CWsWindowGroup *focusWin=CWsTop::FocusWindowGroup();
	while((qPtr=iter++)!=NULL)
		{
		if (qPtr->iCircumstances==EEventControlAlways || 
			(qPtr->iCircumstances==EEventControlOnlyWithKeyboardFocus && qPtr->iWindow->WinGroup()==focusWin) ||
			(qPtr->iCircumstances==EEventControlOnlyWhenVisible && !qPtr->iWindow->TreeIsObscured()))
			aFunc(qPtr, aParam1, aParam2);
		}
	}

void TWindowServerEvent::NotifyOom()
	{
	TTime now;
	now.UniversalTime();
	TTimeIntervalSeconds interval;
	TInt err=now.SecondsFrom(iPrevOomMessageTime,interval);
	if (err!=KErrNone || interval.Int()<0 || interval.Int()>EOomEventSecondGap)
		{
		ProcessErrorMessages(TWsErrorMessage::EDrawingRegion,KErrNoMemory);
		iPrevOomMessageTime=now;
		}
	}

TBool TWindowServerEvent::ProcessErrorMessages(TWsErrorMessage::TErrorCategory aCategory, TInt aError)
	{
	if (aError!=KErrNone)
		{
		ProcessEventQueue(iErrorMessageQueue, SendErrorMessage, aCategory, aError);
		return ETrue;
		}
	return EFalse;
	}

void TWindowServerEvent::ProcessModifierChanges()
	{
	TInt newState=iKeyTranslator->GetModifierState();
	if (newState!=iModifierState)
		{
		TInt changed=iModifierState^newState;
		iModifierState=newState;
		ProcessEventQueue(iModifierChangedQueue, SendModifierChangedEvent, changed, 0);
		}
	}

TEventQueueWalkRet FindScreenDeviceChangedEvent(TAny *aHandlePtr, TWsEvent *aEvent)
	{
	if (aEvent->Type()==EEventScreenDeviceChanged && aEvent->Handle()==*(TUint *)aHandlePtr)
		*(TUint *)aHandlePtr=0;	// Indicates event found
	return(EEventQueueWalkOk);
	}
	
void TWindowServerEvent::SendScreenDeviceChangedEvents(CScreen* aScreen)
	{
	TSglQueIter<TEventRequestItem> iter(iScreenDeviceChangedQueue .Queue());
	TEventRequestItem *qPtr;
	while((qPtr=iter++)!=NULL)
		SendScreenDeviceChangedEvent(qPtr->iWindow);
	if(CClick::IsHandler())
		{
		TClickMakerData clickMakerData;
		clickMakerData.screenDeviceMode=aScreen->ScreenSizeMode();
		CClick::OtherEvent(EEventScreenDeviceChanged, &clickMakerData);
		}
	TWsEvent wsEvent;
	wsEvent.SetType(EEventScreenDeviceChanged);
	TWindowServerEvent::PublishNotification(wsEvent);
	TWservCrEvent crEvent(TWservCrEvent::EScreenSizeModeChanged,aScreen->ScreenSizeMode());
	TWindowServerEvent::NotifyDrawer(crEvent);
	}

void TWindowServerEvent::SendScreenDeviceChangedEvent(const CWsWindowBase *aWindow)
	{
	CEventQueue *queue=aWindow->EventQueue();
	TUint32 handle=aWindow->ClientHandle();
	queue->WalkEventQueue(&FindScreenDeviceChangedEvent,&handle);
	if (handle!=NULL)	// Indicates event not found
		queue->QueueEvent(handle, EEventScreenDeviceChanged);
	}

TEventQueueWalkRet FindGroupChangedEvent(TAny *aHandlePtr, TWsEvent *aEvent)
	{
	if (aEvent->Type()==EEventWindowGroupsChanged && aEvent->Handle()==*(TUint *)aHandlePtr)
		{
		*(TUint *)aHandlePtr=0;	// Indicates event found
		}
	return(EEventQueueWalkOk);
	}
	
void TWindowServerEvent::SendGroupChangedEvents()
	{
	TSglQueIter<TEventRequestItem> iter(iGroupChangedQueue.Queue());
	TEventRequestItem *qPtr;
	while((qPtr=iter++)!=NULL)
		{
		const CWsWindowBase *win=qPtr->iWindow;
		CEventQueue *queue=win->EventQueue();
		TUint32 handle=win->ClientHandle();
		queue->WalkEventQueue(&FindGroupChangedEvent,&handle);
		if (handle!=NULL)	// Indicates event not found
			{
			queue->QueueEvent(handle, EEventWindowGroupsChanged);
			}
		}
	}	

TEventQueueWalkRet FindFocusChangedEvent(TAny *aHandlePtr, TWsEvent *aEvent)
	{
	if (aEvent->Type()==EEventFocusGroupChanged && aEvent->Handle()==*(TUint *)aHandlePtr)
		{
		*(TUint *)aHandlePtr=0;	// Indicates event found
		}
	return(EEventQueueWalkOk);
	}
	
void TWindowServerEvent::SendFocusChangedEvents()
	{
	TInt identifier=0;	// Zero Identifier indicates, currently there is no focused window group
	CScreen* currentFocusScreen=CWsTop::CurrentFocusScreen();	
	TInt screenNumber=currentFocusScreen->ScreenNumber();
	CWsWindowGroup* currentFocusWG=currentFocusScreen->FocusWindowGroup();
	if(currentFocusWG)
		{
		identifier=currentFocusWG->Identifier();
		}
	TWindowServerEvent::NotifyDrawer(TWservCrEvent(TWservCrEvent::EWindowGroupChanged,
		screenNumber, reinterpret_cast<TAny*>(identifier)));
		 
	TSglQueIter<TEventRequestItem> iter(iFocusChangedQueue.Queue());
	TEventRequestItem *qPtr;
	while((qPtr=iter++)!=NULL)
		{
		const CWsWindowBase *win=qPtr->iWindow;
		CEventQueue *queue=win->EventQueue();
		TUint32 handle=win->ClientHandle();
		queue->WalkEventQueue(&FindFocusChangedEvent,&handle);
		if (handle!=NULL)	// Indicates event not found
			{
			queue->QueueEvent(handle, EEventFocusGroupChanged);
			}
		}
	}

TEventQueueWalkRet FindGroupListChangedEvent(TAny *aHandlePtr, TWsEvent *aEvent)
	{
	if (aEvent->Type()==EEventWindowGroupListChanged && aEvent->Handle()==*(TUint *)aHandlePtr)
		{
		*(TUint *)aHandlePtr=0;	// Indicates event found
		}
	return(EEventQueueWalkOk);
	}
	
void TWindowServerEvent::SendGroupListChangedEvents()
	{
	TSglQueIter<TEventRequestItem> iter(iGroupListChangedQueue.Queue());
	TEventRequestItem *qPtr;
	while((qPtr=iter++)!=NULL)
		{
		const CWsWindowBase *win=qPtr->iWindow;
		CEventQueue *queue=win->EventQueue();
		TUint32 handle=win->ClientHandle();
		queue->WalkEventQueue(&FindGroupListChangedEvent,&handle);
		if (handle!=NULL)	// Indicates event not found
			{
			queue->QueueEvent(handle, EEventWindowGroupListChanged);
			}
		}
	}	

TEventQueueWalkRet OverrideVisibilityChangedEvent(TAny *aNewEvent, TWsEvent *aOldEvent)
	{
	// This replaces the first visibility event it finds for the given window with the
	// one given.  This is fine, so long as the meaning of all visibility events remains
	// independent of the ones before.
	TWsEvent* newEvent = static_cast<TWsEvent*>(aNewEvent);
	if (aOldEvent->Type()==EEventWindowVisibilityChanged && aOldEvent->Handle()==newEvent->Handle())
		{
		aOldEvent->SetTimeNow();
		aOldEvent->VisibilityChanged()->iFlags = newEvent->VisibilityChanged()->iFlags;
		newEvent->SetHandle(NULL);
		}
	return EEventQueueWalkOk;
	}

void TWindowServerEvent::SendVisibilityChangedEvents(CWsWindowBase* aWin, TUint aFlags)
	{
	CEventQueue *queue=aWin->EventQueue();
	TWsEvent event;
	event.SetType(EEventWindowVisibilityChanged);
	event.SetHandle(aWin->ClientHandle());
	event.SetTimeNow();
	TWsVisibilityChangedEvent* visevent = event.VisibilityChanged();
	visevent->iFlags = aFlags;
	queue->WalkEventQueue(&OverrideVisibilityChangedEvent,&event);
	if (event.Handle()!=NULL)
		{
		queue->QueueEvent(event);
		}
	}

TEventQueueWalkRet OverrideDisplayChangedEvent(TAny *aNewEvent, TWsEvent *aOldEvent)
	{
	TWsEvent* newEvent = static_cast<TWsEvent*>(aNewEvent);
	if (aOldEvent->Type() == EEventDisplayChanged && 
			aOldEvent->DisplayChanged()->iDisplayNumber == newEvent->DisplayChanged()->iDisplayNumber)
		{
		aOldEvent->SetTimeNow();
		aOldEvent->DisplayChanged()->iConfigurationChangeId = newEvent->DisplayChanged()->iConfigurationChangeId;
		aOldEvent->DisplayChanged()->iResolutionListChangeId = newEvent->DisplayChanged()->iResolutionListChangeId;
		newEvent->DisplayChanged()->iDisplayNumber = KErrNotFound; //So the new event won't be placed on event queue again
		}
	return EEventQueueWalkOk;
	}

TBool TWindowServerEvent::SendDisplayChangedEvents(CWsClient* aWsClient, TInt aDisplayNumber, TInt aConfigurationChangeId, TInt aResolutionListChangeId)
	{
	CEventQueue *queue = aWsClient->EventQueue();
	TWsEvent event;
	event.SetType(EEventDisplayChanged);
	event.SetTimeNow();
	
    // fill in the handle otherwise CONE will discard the notification
    CWsObjectIx* clientObjList = aWsClient->ObjectIndex();
    const TWsObject* ptr=clientObjList->FirstObject();
    const TWsObject* end=ptr+clientObjList->Length();
    while(++ptr<end)    // first one should always have a NULL object
        {
        const CWsObject* obj=ptr->iObject;
        if (obj && obj->Type()==WS_HANDLE_GROUP_WINDOW)
            {
            event.SetHandle(ptr->iHandle);
            break;
            }
        }	
	
	TWsDisplayChangedEvent* dispEvent = event.DisplayChanged();
	dispEvent->iDisplayNumber = aDisplayNumber;
	dispEvent->iConfigurationChangeId = aConfigurationChangeId;
	dispEvent->iResolutionListChangeId = aResolutionListChangeId;
	queue->WalkEventQueue(&OverrideDisplayChangedEvent, &event);
	//place the new event on the queue only when its display number is valid (!=KErrNotFound)
	if(event.DisplayChanged()->iDisplayNumber >= 0)
		{
		return queue->QueueEvent(event);
		}
	return ETrue;
	}

void TWindowServerEvent::QueueKeyEvent(CWsWindowGroup *aWin, TWsEvent &aEvent, TWservEventPriorities aPriority)
	{
	aEvent.SetTimeNow();
	aWin->EventQueue()->QueueEvent(aEvent, aPriority);
	}

void TWindowServerEvent::QueueKeyPress(const TKeyData& aKey, TInt aScanCode, CWsWindowGroup* aRepeatFocus, TBool aCheckRepeat,TInt aRepeats)
 	{
	CWsWindowGroup* focusWin=CWsTop::FocusWindowGroup();
	TWsEvent event;
	TKeyEvent& keyEvent=*event.Key();
	keyEvent.iCode=aKey.iKeyCode;
	keyEvent.iScanCode=aScanCode;
	keyEvent.iModifiers=aKey.iModifiers;
	keyEvent.iRepeats=aRepeats;
	if (!aRepeatFocus && CClick::IsHandler())
		CClick::KeyEvent(EEventKey,keyEvent);
	CWsCaptureLongKey* longCapture=NULL;
	if (aCheckRepeat)
		longCapture=CWsCaptureLongKey::CheckForCapture(aKey.iKeyCode, aKey.iModifiers);
	if (aKey.iIsCaptureKey)
		{
		if (aKey.iApp==NULL)	// Captured by Wserv itself
			{
			_LIT(KWSERVDebugLogCapturedKey,"WSERV Captured Key");
			CScreen* focusScreen=CWsTop::CurrentFocusScreen();
			TInt screenNo=focusScreen->ScreenNumber();
			
			if (wsDebugLog)
				wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogCapturedKey);
			CWsHotKey *hotKey=iHotKeys;
			while(hotKey)
				{
				if (hotKey->KeyHandle()==aKey.iHandle)
					{
					switch(hotKey->HotKeyType())
						{
						case EHotKeyEnableLogging:
							CWsTop::EnableLogging();
							break;
						case EHotKeyDisableLogging:
							CWsTop::DisableLogging();
							break;
						case EHotKeyStateDump:
							StateDump();
							break;
						case EHotKeyHeapDump:
							HeapDump();
							break;
						case EHotKeyOfDeath:
							if (!CWsPassword::PasswordModeActive())
								{
								const TBool currentJustInTimeValue=User::JustInTime();
								if (currentJustInTimeValue)
									{
									User::SetJustInTime(EFalse);
									}
								CWsTop::KillForegroundSession();
								if (currentJustInTimeValue)
									{
									User::SetJustInTime(ETrue);
									}
								}
							break;
						case EHotKeyShutDown:
							CWsTop::Exit();
							break;
						case EHotKeyIncContrast:
							focusScreen->IncContrast();
							break;
						case EHotKeyDecContrast:
							focusScreen->DecContrast();
							break;
						case EHotKeyOff:
							CWsTop::HandleSwitchOff(EEventKeySwitchOff,ETrue);
							break;
						case EHotKeyBacklightToggle:
							{
							TInt state;
							if (!ProcessErrorMessages(TWsErrorMessage::EBackLight, HAL::Get(screenNo,HALData::EBacklightState,state)))
								ProcessErrorMessages(TWsErrorMessage::EBackLight, HAL::Set(screenNo,HALData::EBacklightState,!state));
							}
							break;
						case EHotKeyBacklightOn:
							ProcessErrorMessages(TWsErrorMessage::EBackLight, HAL::Set(screenNo,HALData::EBacklightState,ETrue));
							break;
						case EHotKeyBacklightOff:
							ProcessErrorMessages(TWsErrorMessage::EBackLight, HAL::Set(screenNo,HALData::EBacklightState,EFalse));
							break;
						case EHotKeyScreenDimension0:
						case EHotKeyScreenDimension1:
						case EHotKeyScreenDimension2:
						case EHotKeyScreenDimension3:
							focusScreen->doSetScreenMode(hotKey->HotKeyType()-EHotKeyScreenDimension0);
							break;
						case EHotKeyCycleDisplaySize:
							focusScreen->CycleDisplaySize();
							break;
						case EHotKeyCycleOrientation:
							focusScreen->CycleOrientation();
							break;
						case EHotKeyIncBrightness:
							focusScreen->IncBrightness();
							break;
						case EHotKeyDecBrightness:
							focusScreen->DecBrightness();
							break;
						case EHotKeyCycleFocusScreen:
							CWsTop::SetCurrentFocusScreen((CWsTop::CurrentFocusScreen()->ScreenNumber()+1)%CWsTop::NumberOfScreens());
							break;
						}
					return;
					}
				hotKey=hotKey->iNext;
				}
			WS_PANIC_ALWAYS(EWsPanicUnknownCaptureKey);
			return;
			}
		focusWin=((CWsWindowGroup *)aKey.iApp);
		_LIT(KWSERVDebugLogKeyCapturedByApp,"Key captured by app %d");
		if (wsDebugLog)
			wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogKeyCapturedByApp,focusWin->Identifier());
		if (CWsPassword::PasswordModeActive() && focusWin!=CWsPassword::PasswordWindow()->WinGroup())
			return;
		}
	if (aRepeatFocus && aRepeatFocus!=focusWin)
		CKeyboardRepeat::CancelRepeat(NULL);		// Repeat is going to different window so cancel it and don't deliver this key
	else if (focusWin!=NULL && focusWin->CheckForPriorityKey(aKey,aScanCode)==EFalse)
		{
		if (longCapture || (aCheckRepeat && !aRepeatFocus && aKey.iModifiers&EModifierAutorepeatable))
			{
			if (CKeyboardRepeat::StartRepeat(aKey,aScanCode,focusWin,longCapture))
				return;
			}
		event.SetType(EEventKey);
		event.SetHandle(focusWin->ClientHandle());
		if (aRepeats!=0)
			{
			CEventQueue* queue=focusWin->EventQueue();
			queue->Wait();
			const TWsEvent* prev=queue->PeekLastEvent();
			if (prev!=NULL && prev->Type()==EEventKey && prev->Key()->iRepeats>0)
				{
				event= *prev;
				event.Key()->iRepeats+=aRepeats;
				queue->UpdateLastEvent(event);
				queue->Signal();
				if (CClick::IsHandler())
					CClick::KeyEvent(EEventKeyRepeat,*event.Key());
				return;
				}
			queue->Signal();
			event.Key()->iRepeats=aRepeats;
			if (CClick::IsHandler())
				CClick::KeyEvent(EEventKeyRepeat,keyEvent);
			}
		QueueKeyEvent(focusWin, event, EEventPriorityLow);
		}
	}

void TWindowServerEvent::QueueKeyUpDown(const TRawEvent &aRawEvent)
 	{
	CWsWindowGroup *focusWin=CWsCaptureKeyUpsAndDowns::CheckForCapture(aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE, iModifierState);
	if (!focusWin)	// If not captured
		focusWin=CWsTop::FocusWindowGroup();
	TWsEvent event;
	TEventCode type=aRawEvent.Type()==TRawEvent::EKeyUp ? EEventKeyUp : EEventKeyDown;
	event.Key()->iCode=0;
#if defined(__WINS__)
	if (focusWin && !focusWin->WsOwner()->RemoveKeyCode())
		event.Key()->iScanCode=aRawEvent.ScanCode();
	else
#endif
	event.Key()->iScanCode=aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE;
	event.Key()->iModifiers=iModifierState;
	event.Key()->iRepeats=0;
	if (CClick::IsHandler())
		CClick::KeyEvent(type,*event.Key());
	if (focusWin!=NULL)
		{
		event.SetType(type);
		event.SetHandle(focusWin->ClientHandle());
		QueueKeyEvent(focusWin, event, EEventPriorityHigh);
		}
	}

LOCAL_D void GetPointerEvent(TPointerEvent::TType& aType, const TRawEvent &aRawEvent, TBool& aHandled)
	{
	aHandled=ETrue;
	switch(aRawEvent.Type())
		{
	case TRawEvent::EButton1Down:
		aType=TPointerEvent::EButton1Down;
		break;
	case TRawEvent::EButton1Up:
		aType=TPointerEvent::EButton1Up;
		break;
	case TRawEvent::EButton2Down:
		aType=TPointerEvent::EButton2Down;
		break;
	case TRawEvent::EButton2Up:
		aType=TPointerEvent::EButton2Up;
		break;
	case TRawEvent::EButton3Down:
		aType=TPointerEvent::EButton3Down;
		break;
	case TRawEvent::EButton3Up:
		aType=TPointerEvent::EButton3Up;
		break;
	case TRawEvent::EPointerMove:
		aType=TPointerEvent::EMove;
		break;
	case TRawEvent::EPointerSwitchOn:
		aType=TPointerEvent::ESwitchOn;
		break;
	case TRawEvent::EPointer3DOutOfRange:
		aType=TPointerEvent::EOutOfRange;
		break;
	default:
		aHandled=EFalse;
		}
	}

TBool TWindowServerEvent::MousePress(const TRawEvent &aRawEvent, const CWsWindowGroup *aGroupWin)
	//
	//Return EFalse if known not to be a Mouse Event
	//
	{
	TBool handled=ETrue;
	TPointerEvent::TType type;
	GetPointerEvent(type, aRawEvent, handled);
	if (handled)
		{
		TPoint3D point3D(0,0,0);
		if (type != TPointerEvent::EOutOfRange)
			{
			point3D = aRawEvent.Pos3D();
			}
		TWsEvent event;
		TAdvancedPointerEventHelper::InitAdvancedPointerEvent(event, type,iKeyTranslator->GetModifierState(),point3D,aRawEvent.PointerNumber());
		TWsPointer::ProcessWsEvent(event, aGroupWin, ETrue);
		}
	return handled;
	}

LOCAL_D void SendEventToKeyClick(const TRawEvent& aRawEvent)
	{
	switch(aRawEvent.Type())
		{
		case TRawEvent::EKeyDown:
		case TRawEvent::EKeyUp:
			{
			TKeyEvent keyEvent;
			keyEvent.iCode=0;
			keyEvent.iScanCode=aRawEvent.ScanCode();
			keyEvent.iModifiers=0;
			keyEvent.iRepeats=0;
			CClick::KeyEvent(EEventKey,keyEvent);
			}
			break;
		case TRawEvent::EButton1Down:
		case TRawEvent::EButton1Up:
		case TRawEvent::EButton2Down:
		case TRawEvent::EButton2Up:
		case TRawEvent::EButton3Down:
		case TRawEvent::EButton3Up:
		case TRawEvent::EPointerMove:
		case TRawEvent::EPointerSwitchOn:
			{
			TBool handled=ETrue;
			TPointerEvent::TType type;
			GetPointerEvent(type, aRawEvent, handled);
			if (handled)
				{
				TWsEvent event;
				TAdvancedPointerEventHelper::InitAdvancedPointerEvent(event, type, 0, aRawEvent.Pos3D(), TPoint(), aRawEvent.PointerNumber());
				TAdvancedPointerEvent& pointerEvent = *event.Pointer();
				CClick::PointerEvent(pointerEvent.iPosition,pointerEvent);
				}
			}
			break;
		default:
			break;
		}
	}

void TWindowServerEvent::ProcessRawEvent(const TRawEvent& aRawEvent)
//
// Event has completed.
//
	{
	TRawEvent::TType eventType = aRawEvent.Type();
	TBool isPointerEvent = TWsPointer::IsPointerEventType(eventType);
	if (isPointerEvent)
		{
		TWsPointer::UpdatePrimaryPointer(aRawEvent);
		}
	TInt count=iEventHandlers.Count();
	TInt ii;
	TBool eventHandled = EFalse;
	iEventHandlerCount++;
	for(ii=0;ii<count;++ii)
		{
		TRawEventHandler &handler = iEventHandlers[ii];
		if (handler.iEventHandler != NULL &&
			(!isPointerEvent ||
			 handler.iAdvancedPointersEnabled ||
			 aRawEvent.PointerNumber() == TWsPointer::PrimaryPointer()) &&
			handler.iEventHandler->OfferRawEvent(aRawEvent))
			{
			if (CClick::IsHandler())
				{
				SendEventToKeyClick(aRawEvent);
				}
			eventHandled = ETrue;
			break;
			}
		}
	if (--iEventHandlerCount == 0)
		{
		if (ERemovedEventHandlerWhileProcessingRawEvents & iBinaryFlags) // Handler was deleted while previous loop
			{ 
			iBinaryFlags &= ~ERemovedEventHandlerWhileProcessingRawEvents;
			for(ii=count-1;ii>=0;--ii)
				{
				if (iEventHandlers[ii].iEventHandler==NULL) iEventHandlers.Remove(ii);
				}
			}
		}
	if (eventHandled)
		{
		if (isPointerEvent)
			{
			TWsPointer::RollbackPrimaryPointer();
			}
		return;
		}
	switch(eventType)
		{
		case TRawEvent::ERedraw:
			CWsTop::RedrawScreens();
			break;
		case TRawEvent::ESwitchOn:
		case TRawEvent::ECaseOpen:
			{
			TInt event=EEventCaseOpened;
			CKeyboardRepeat::CancelRepeat(NULL);
			CWsPassword::SwitchOn();
			if (eventType==TRawEvent::ESwitchOn)
				{
				UserSvr::WsSwitchOnScreen();
				HAL::Set(HALData::EDisplayState,1);
				event=EEventSwitchOn;
				}
			ProcessEventQueue(iSwitchOnQueue, SendSwitchOnEvent, event, 0);
			break;
			}
		case TRawEvent::ESwitchOff:
		case TRawEvent::ECaseClose:
			{
			TBool switchOff=(eventType==TRawEvent::ESwitchOff);
			CWsTop::HandleSwitchOff(switchOff? EEventSwitchOff:EEventCaseClosed,switchOff);
			break;
			}
#ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP			
		case TRawEvent::ERestartSystem:
			{ /* restart event being handled */
			CWsTop::HandleSwitchOff(EEventRestartSystem,ETrue);
			break;
			}
#endif			
		case TRawEvent::EInactive:
#ifndef __WINS__
			CWsTop::WindowServer()->AnimationScheduler()->OnInactive();
#endif
			CKeyboardRepeat::CancelRepeat(NULL);
			break;
		case TRawEvent::EActive:
#ifndef __WINS__
			CWsTop::WindowServer()->AnimationScheduler()->OnActive();
#endif
			break;
		case TRawEvent::EKeyDown:
			{
			_LIT(KWSERVDebugLogKeyDownArrival,"Key down arrives %d");
			CScreen* screen = CWsTop::Screen();
			WS_ASSERT_ALWAYS(screen, EWsPanicNoScreen);
			if(CDebugBar* dbg = screen->DebugBar())
				dbg->OnKeyEvent();
			if (wsDebugLog)
				wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogKeyDownArrival,aRawEvent.ScanCode());
			CKeyboardRepeat::KeyDown();
			TKeyData keyData;
			TBool translated=iKeyTranslator->TranslateKey(aRawEvent.ScanCode(), EFalse,*iCaptureKeys,keyData);
			ProcessModifierChanges();
			QueueKeyUpDown(aRawEvent);
			if (translated)
				QueueKeyPress(keyData,aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE,NULL,ETrue,0);
			}
			break;
		case TRawEvent::EKeyUp:
			{
			_LIT(KWSERVDebugLogKeyUpArrival,"Key up arrives %d");
			CScreen* screen = CWsTop::Screen();
			WS_ASSERT_ALWAYS(screen, EWsPanicNoScreen);
			if(CDebugBar* dbg = screen->DebugBar())
				dbg->OnKeyEvent();
			if (wsDebugLog)
				wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogKeyUpArrival,aRawEvent.ScanCode());
			TKeyData keyData;
			CKeyboardRepeat::KeyUp(aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE);
			TBool translated=iKeyTranslator->TranslateKey(aRawEvent.ScanCode(), ETrue,*iCaptureKeys,keyData);
			ProcessModifierChanges();
			QueueKeyUpDown(aRawEvent);
			if (translated)
				{
				CKeyboardRepeat::CancelRepeat(NULL);
				QueueKeyPress(keyData,aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE,NULL,EFalse,0);
				}
			}
			break;
		case TRawEvent::EButton1Down:
		case TRawEvent::EButton2Down:
		case TRawEvent::EButton3Down:
		case TRawEvent::EPointerSwitchOn:
#ifndef __WINS__
			CWsTop::WindowServer()->AnimationScheduler()->OnActive();
#endif
			// fall through
		case TRawEvent::EButton1Up:
		case TRawEvent::EButton2Up:
		case TRawEvent::EButton3Up:
		case TRawEvent::EPointerMove:
		case TRawEvent::EPointer3DOutOfRange:
			#if defined(_DEBUG)
				WS_ASSERT_DEBUG(MousePress(aRawEvent,NULL), EWsPanicEventType);
			#else
				MousePress(aRawEvent,NULL);
			#endif
			break;
		case TRawEvent::EUpdateModifiers:
			iKeyTranslator->UpdateModifiers(aRawEvent.Modifiers());
			break;
		case TRawEvent::EKeyRepeat:
 			{
 			_LIT(KWSERVDebugLogRepeatingKeyArrival,"Repeating key arrives %d");
 			if (wsDebugLog)
 				wsDebugLog->MiscMessage(CDebugLogBase::ELogEverything,KWSERVDebugLogRepeatingKeyArrival,aRawEvent.ScanCode());
 			TKeyData keyData;
 			keyData.iModifiers=iKeyTranslator->GetModifierState();
			keyData.iApp=0;
			keyData.iHandle=0;
			keyData.iIsCaptureKey=EFalse;
			keyData.iKeyCode=aRawEvent.ScanCode(); 
			iCaptureKeys->ProcessCaptureKeys(keyData);
			QueueKeyPress(keyData, aRawEvent.ScanCode() __REMOVE_WINS_CHARCODE,NULL,EFalse,aRawEvent.Repeats());
 			}
 			break;
		default:
			break;
		}
	}

void TWindowServerEvent::ProcessKeyEvent(const TKeyEvent &aKeyEvent,TInt aRepeats)
	{
	TKeyData keyData;
	keyData.iModifiers=aKeyEvent.iModifiers;
	keyData.iApp=0;
	keyData.iHandle=0;
	keyData.iIsCaptureKey=EFalse;
	keyData.iKeyCode=aKeyEvent.iCode;
	if (CKeyboardRepeat::IsAreadyActive())
		{
		CKeyboardRepeat::CancelRepeat(NULL);
		}
	iCaptureKeys->ProcessCaptureKeys(keyData);
	QueueKeyPress(keyData,aKeyEvent.iScanCode,NULL,aRepeats==0,aRepeats);
	}

void TWindowServerEvent::AddCaptureKeyL(const TCaptureKey &aCaptureKey)
	{
	iCaptureKeys->AddCaptureKeyL(aCaptureKey,aCaptureKey.iKeyCodePattern.iFiller);
	}

void TWindowServerEvent::SetCaptureKey(TUint32 aHandle, const TCaptureKey &aCaptureKey)
	{
	iCaptureKeys->SetCaptureKey(aHandle, aCaptureKey,aCaptureKey.iKeyCodePattern.iFiller);
	}

void TWindowServerEvent::CancelCaptureKey(TUint32 aHandle)
	{
	iCaptureKeys->CancelCaptureKey(aHandle);
	}

TInt TWindowServerEvent::GetModifierState()
	{
	return(iKeyTranslator->GetModifierState());
	}

void TWindowServerEvent::SetModifierState(TEventModifier aModifier,TModifierState aState)
	{
	iKeyTranslator->SetModifierState(aModifier,aState);
	}

TInt TWindowServerEvent::AddNotificationHandler(CAnim* aAnim, TUint32 aNotifications)
	{
	SNotificationHandler notif;
	notif.iAnim = aAnim;
	notif.iNotifications = aNotifications;

	// update the entry if the anim is already in the array
	TInt count=iNotificationHandlers->Count();
	TInt ii;
	for(ii=0;ii<count;++ii)
		{
		if ((*iNotificationHandlers)[ii].iAnim==aAnim)
			{
			(*iNotificationHandlers)[ii]=notif;
			return KErrNone;
			}
		}
	
	// otherwise add it to the array
	TRAPD(err,iNotificationHandlers->AppendL(notif));
	return err;
	}

void TWindowServerEvent::RemoveNotificationHandler(CAnim* aAnim)
	{
	TInt count=iNotificationHandlers->Count();
	TInt ii;
	for(ii=0;ii<count;++ii)
		{
		if ((*iNotificationHandlers)[ii].iAnim==aAnim)
			{
			iNotificationHandlers->Delete(ii);
			return;
			}
		}
	}

void TWindowServerEvent::PublishNotification(const TWsEvent& aWsEvent)
	{
	TInt count=iNotificationHandlers->Count();
	TInt ii;
	for(ii=0;ii<count;++ii)
		{
		SNotificationHandler notif = (*iNotificationHandlers)[ii];
		switch (aWsEvent.Type())
			{
		case EEventDirectScreenAccessBegin:
		case EEventDirectScreenAccessEnd:
			if (notif.iNotifications & EDirectScreenAccess)
				{
				notif.iAnim->HandleNotification(aWsEvent);
				}
			break;
		case EEventHeartbeatTimerStateChange:
			if (notif.iNotifications & EHeartbeatTimer)
				{
				notif.iAnim->HandleNotification(aWsEvent);
				}
			break;
		case EEventScreenDeviceChanged:
			if (notif.iNotifications & EScreenDeviceChange)
				{
				notif.iAnim->HandleNotification(aWsEvent);
				}
			break;
		default:
			break;
			}
		}

	}

TBool TWindowServerEvent::DrawerCompareFunc(const TDrawerHandler& lhs, const TDrawerHandler& rhs)
	{
	return lhs.iDrawer == rhs.iDrawer;	
	}

TInt TWindowServerEvent::RegisterDrawerHandler(CWsGraphicDrawer* aDrawer, TUint32 aEvents)
	{
	TInt idx = iDrawerHandlers->Find(TDrawerHandler(aDrawer, aEvents),
		TIdentityRelation<TDrawerHandler>(TWindowServerEvent::DrawerCompareFunc));
	if (idx != KErrNotFound)
		{
		// replace event mask for this drawer
		(*iDrawerHandlers)[idx].iEvents = aEvents;
		idx = KErrNone;
		}
	else
		idx = iDrawerHandlers->Append(TDrawerHandler(aDrawer,aEvents));
	
	return idx;
	}

TInt TWindowServerEvent::UnregisterDrawerHandler(CWsGraphicDrawer* aDrawer)
	{
	TInt idx = iDrawerHandlers->Find(TDrawerHandler(aDrawer,0),
		TIdentityRelation<TDrawerHandler>(TWindowServerEvent::DrawerCompareFunc));
	if (idx == KErrNotFound)
		return idx;
	(*iDrawerHandlers)[idx].iDrawer = NULL;		//NotifyDrawer() will clean up the array
	return KErrNone;
	}

TInt TWindowServerEvent::RegisterWsEventHandler(MWsEventHandler * aHandler, TUint32 aEvents)
	{
	TWsEventHandler handler(aHandler, aEvents);
	TInt idx = iWsEventHandlers.Find(handler, TIdentityRelation<TWsEventHandler>(TWsEventHandler::CompareHandler));
	if (idx < 0)
		{
		TInt err = iWsEventHandlers.Append(handler);
		return err;
		}
	else
		{
		iWsEventHandlers[idx].iEvents = aEvents;
		return KErrNone;
		}
	}
	
TInt TWindowServerEvent::UnregisterWsEventHandler(MWsEventHandler * aHandler)
	{
	TWsEventHandler handler(aHandler, 0);
	TInt idx = iWsEventHandlers.Find(handler, TIdentityRelation<TWsEventHandler>(TWsEventHandler::CompareHandler));
	if (idx < 0)
		return idx;
	iWsEventHandlers[idx].iEvents = NULL;	//NotifyDrawer() will clean up the array
	return KErrNone;
	}


void TWindowServerEvent::NotifyDrawer(const TWservCrEvent& aEvent)
	{
	TInt drawerCount = iDrawerHandlers->Count();
	for (TInt idx = 0; idx < drawerCount; idx++)
		{
		TDrawerHandler hd = (*iDrawerHandlers)[idx]; 
		if (!hd.iDrawer) 
			{                					//If the handler has been removed 
			iDrawerHandlers->Remove(idx);       //Remove from the array 
			drawerCount -= 1;   				//Update the counters 
			idx -= 1; 
			} 
		else 
			{ 
			if (hd.iEvents & aEvent.Type()) 
				{ 
			    hd.iDrawer->HandleEvent(aEvent); 
			    } 
			} 
		}
	
	TInt eventHandlerCount = iWsEventHandlers.Count();
	for (TInt idx = 0; idx < eventHandlerCount; ++idx)
		{
		TWsEventHandler* eh = &iWsEventHandlers[idx];
		if (!eh->iEvents)
			{								//If the handler has been removed
			iWsEventHandlers.Remove(idx);	//Remove from the array
			eventHandlerCount -= 1;			//Update the counters
			idx -= 1;
			}
		else
			{
			if (eh->iEvents & aEvent.Type())
				{
				eh->iHandler->DoHandleEvent(aEvent);
				}
			}
		}
	}

void TWindowServerEvent::NotifyScreenDrawingEvent(const TRegion* aRegion)
	{
	if (aRegion && !aRegion->IsEmpty())
		{
		TWservCrEvent event(TWservCrEvent::EScreenDrawing,0,const_cast<TRegion*>(aRegion));
		NotifyDrawer(event);
		}
	}

void TWindowServerEvent::NotifyScreenDrawingEvent(const TRect& aRect)
	{
	TRegionFix<1> reg(aRect);
	TWservCrEvent event(TWservCrEvent::EScreenDrawing,0,&reg);
	NotifyDrawer(event);
	}

//
// CRawEventReceiver //
//

CRawEventReceiver::CRawEventReceiver(TInt aPriority) : CActive(aPriority)
//
// Constructor
//
	{
	__DECLARE_NAME(_S("CRawEventReceiver"));
	}

CRawEventReceiver::~CRawEventReceiver()
	{
	CActive::Cancel();
	}

void CRawEventReceiver::ConstructL()
	{
	CActiveScheduler::Add(this);
	UserSvr::CaptureEventHook();
	Request();
	}

void CRawEventReceiver::Request()
//
// Issue a request for the next event.
//
	{
	UserSvr::RequestEvent(iEventBuf,iStatus);
	SetActive();
	}

void CRawEventReceiver::DoCancel()
//
// Cancel a pending event.
//
	{
	UserSvr::RequestEventCancel();
	}

void CRawEventReceiver::RunL()
	{
//__PROFILE_START(11);
	if (TWsPointer::PreProcessDriverEvent(iEventBuf.Event()
#if defined(__WINS__)
													,ETrue
#endif
														  ))
		TWindowServerEvent::ProcessRawEvent(iEventBuf.Event());
	Request();
//__PROFILE_END(11);
	}

//
// TEventRequestQueue //
//

TEventRequestQueue::TEventRequestQueue() : iQueue(_FOFF(TEventRequestItem,iQue))
	{}

inline TSglQue<TEventRequestItem> &TEventRequestQueue::Queue()
	{return(iQueue);}

TEventRequestItem *TEventRequestQueue::FindInEventRequestQueueList(const CWsWindowBase &aWindow)
//
// Return a pointer to the link in the queue for the window, or NULL if not in the queue
//
	{
	TSglQueIter<TEventRequestItem> iter(iQueue);
	TEventRequestItem *qPtr;
	while((qPtr=iter++)!=NULL)
		if (qPtr->iWindow==&aWindow)
			break;
	return(qPtr);
	}

void TEventRequestQueue::AddToEventRequestListL(const CWsWindowBase &aWindow, TInt aParam, TEventControl aCircumstances)
//
// Add a link to the on event list
//
	{
	TEventRequestItem *item=FindInEventRequestQueueList(aWindow);
	if (!item)
		{
		item=new(ELeave) TEventRequestItem;
		item->iWindow= &aWindow;
		item->iParam=aParam;
		item->iCircumstances=aCircumstances;
		iQueue.AddFirst(*item);
		}
	item->iCircumstances=aCircumstances;
	item->iParam=aParam;	// Just update the parameter if already exists
	}

void TEventRequestQueue::RemoveFromEventRequestListL(const CWsWindowBase &aWindow)
//
// Remove a link from the on event list
//
	{
	TEventRequestItem *qPtr=FindInEventRequestQueueList(aWindow);
	if (qPtr)
		{
		iQueue.Remove(*qPtr);
		delete qPtr;
		}
	}

//
// Keyboard auto repeat class //
//

CKeyboardRepeat::CKeyboardRepeat() : CTimer(EKeyRepeatPriority)
	{}

void CKeyboardRepeat::NewL()
	{
	iThis=new(ELeave) CKeyboardRepeat();
	iThis->ConstructL();
	CActiveScheduler::Add(iThis);
	_LIT(KWSERVIniFileVarRepeatRollover,"REPEATROLLOVER");
	WsIniFile->FindVar(KWSERVIniFileVarRepeatRollover,iRepeatRollover);
	}

void CKeyboardRepeat::Destroy()
	{
	delete iThis;
	}

void CKeyboardRepeat::GetRepeatTime(TTimeIntervalMicroSeconds32 &aInitialTime, TTimeIntervalMicroSeconds32 &aTime)
	{
	aInitialTime=iInitialTime;
	aTime=iTime;
	}

void CKeyboardRepeat::SetRepeatTime(const TTimeIntervalMicroSeconds32 &aInitialTime, const TTimeIntervalMicroSeconds32 &aTime)
	{
	iInitialTime=aInitialTime;
	iTime=aTime;
	}

void CKeyboardRepeat::RunL()
	{
	User::ResetInactivityTime();
	//WS_ASSERT_DEBUG(iRepeating!=ERepeatNone, EWsPanicTemp);
	TBool timer=ETrue;
	if (iRepeating>=ERepeatLong)
		{
		// Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong
		if (iLongCapture)
			{
			iCurrentRepeat.iKey.iApp=REINTERPRET_CAST(TUint32,iLongCapture->iWindowGroup);
			iCurrentRepeat.iKey.iHandle=0;
			iCurrentRepeat.iKey.iIsCaptureKey=ETrue;
			iCurrentRepeat.iKey.iKeyCode=iLongCapture->iData.outputKey;
			timer=iLongCapture->iData.flags&ELongCaptureRepeatEvents;
			iRepeating=ERepeatLongRepeated;
			}
		else
			{
			// Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong
			// Stop key repeat if this incorrect condition occurs
			timer=EFalse; 
			}		
		}
	if (timer)
		After(iTime);
	else
		iRepeating=ERepeatNone;
	TWindowServerEvent::QueueKeyPress(iCurrentRepeat.iKey,iCurrentRepeat.iScanCode,iFocus,EFalse,1);
	}

TBool CKeyboardRepeat::StartRepeat(const TKeyData &aKey, TInt aScanCode, CWsWindowGroup *aRepeatFocus, CWsCaptureLongKey* aLongCapture)
	{
	TTimeIntervalMicroSeconds32 time;
	TBool ret=EFalse;
	iCurrentRepeat.iScanCode=aScanCode;
	iCurrentRepeat.iKey=aKey;

	if (aLongCapture)
		{
		iLongCapture=aLongCapture;
		iRepeating=ERepeatLong;
		time=aLongCapture->iData.delay;
		ret=!(aLongCapture->iData.flags&ELongCaptureShortEventImmediately);
		//need window group from long capture key or even better delete it altogether.
		iFocus=aLongCapture->WindowGroup();
		}
	else
		{
		iFocus=aRepeatFocus;
		iRepeating=ERepeatNormal;
		time=iInitialTime;
		}
	iThis->After(time);
	return ret;
	}

void CKeyboardRepeat::doCancelRepeat()
	{
	iRepeating=ERepeatNone;
	iThis->Cancel();
	}

void CKeyboardRepeat::CancelRepeat(CWsWindowGroup *aRepeatFocus)
	{
	if (aRepeatFocus==NULL || aRepeatFocus==iFocus)
		{
		if (iRepeating)
			doCancelRepeat();
		iAlternateRepeatExists=EFalse;
		}
	else if (iRepeating >= ERepeatLong)
		{
		// Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong
		if (iLongCapture && iLongCapture->iWindowGroup == aRepeatFocus)
			{
			doCancelRepeat();
			iAlternateRepeatExists=EFalse;
			}
		}
	}

void CKeyboardRepeat::CancelRepeat(CWsWindowGroup *aRepeatFocus,TUint aScanCode,TBool aLongCaptureFlag,TUint aModifiers)
	{
	if (aLongCaptureFlag)
		{
		// long capture key is cancelled
		if (iRepeating >= ERepeatLong && iCurrentRepeat.iScanCode==aScanCode)			
				{
				// Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong
				if (iLongCapture && aRepeatFocus == iLongCapture->iWindowGroup &&
					(aModifiers & iLongCapture->iData.modifierMask) == iLongCapture->iData.modifiers)
					{
					doCancelRepeat();
					iAlternateRepeatExists=EFalse;
					}
				}
		}
	else
		{
		// normal capture key is cancelled
		if (aRepeatFocus==iFocus)
			{
			if (iRepeating>=ERepeatNormal && iCurrentRepeat.iScanCode==aScanCode)
				{
				doCancelRepeat();
				}
			iAlternateRepeatExists=EFalse;
			}
		}
	}
	
void CKeyboardRepeat::KeyDown()
	{
	if (iRepeating!=ERepeatNone)
		{
		if (iRepeating==ERepeatNormal && iRepeatRollover>0) // 1 Allow key repeat rollover
			{
			iAlternateRepeat=iCurrentRepeat;
			iAlternateRepeatExists=ETrue;
			}
		doCancelRepeat();
		}
	}

void CKeyboardRepeat::KeyUp(TInt aScanCode)
	{
	if (iAlternateRepeatExists && iAlternateRepeat.iScanCode==aScanCode)
		iAlternateRepeatExists=EFalse;
	if (iRepeating!=ERepeatNone && iCurrentRepeat.iScanCode==aScanCode)
		{
		if (iRepeating==ERepeatLong)
			{
			// Defensive programming - iLongCapture should never be NULL if iRepeating >= ERepeatLong			
			if (iLongCapture && !(iLongCapture->iData.flags&ELongCaptureShortEventImmediately))
				{
				TWindowServerEvent::QueueKeyPress(iCurrentRepeat.iKey,iCurrentRepeat.iScanCode,NULL,EFalse,0);	
				}
			}			
		if (iAlternateRepeatExists)
			{
			iAlternateRepeatExists=EFalse;
			iCurrentRepeat=iAlternateRepeat;
			iRepeating=ERepeatNormal;
			}
		else
			doCancelRepeat();
		}
	}

//
// CWsHotKey //
//

CWsHotKey::CWsHotKey(TInt aHotKeyType, TBool aIsDefault) : 
	iHotKeyType(aHotKeyType),
	iIsDefault(aIsDefault)
	{
	}

CWsHotKey::~CWsHotKey()
	{
	delete iCaptureKey;
	}

void CWsHotKey::ConstructLD(const TWsWinCmdCaptureKey &aCaptureKey)
	{
	CleanupStack::PushL(this);
	iCaptureKey=new(ELeave) CWsCaptureKey(NULL);
	iCaptureKey->ConstructL(aCaptureKey);
	CleanupStack::Pop();
	}

void CWsHotKey::SetL(const TWsWinCmdCaptureKey &aCaptureKey)
	{
	iCaptureKey->SetL(aCaptureKey);
	}

//
//CEventQueueRetry//
//
CEventQueueRetry* CEventQueueRetry::NewL()
	{
	CEventQueueRetry* self = new (ELeave) CEventQueueRetry;
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}
      
void CEventQueueRetry::ConstructL()
	{
	User::LeaveIfError(iTimer.CreateLocal());
	CActiveScheduler::Add(this);
	}
 
CEventQueueRetry::CEventQueueRetry() : CActive(EPriorityStandard), iRetrySpinner(1)
	{
	
	}

CEventQueueRetry::~CEventQueueRetry()
	{
	Cancel();
	iTimer.Close();
	iClientArray.Close();
	}

void CEventQueueRetry::DoCancel()
	{
	iTimer.Cancel();
	iRetrySpinner = 0;
	iClientArray.Reset();
	}

void CEventQueueRetry::RunL()
	{
	//some clients may be no longer interested in listening
	//so we need to refresh the client list each round of retry
	iClientArray.Reset();
	TInt err = iOwner->GetNotificationClients(iClientArray);
	if(err != KErrNone)
		{
		iClientArray.Reset(); //so the retry won't kick off
		}
	if(iClientArray.Count() > 0)
		{
		TBool eventOnAllQueues = ETrue;
		for(TInt i = 0; i < iClientArray.Count(); i++)
			{
			if(iClientArray[i]->RetryEvent(EEventDisplayChanged))
				{
				if(TWindowServerEvent::SendDisplayChangedEvents(iClientArray[i], iOwner->ScreenNumber(),
						iOwner->ConfigSpinner(), iOwner->DisplaySpinner()))
					{
					iClientArray[i]->RemoveRetryFlag(EEventDisplayChanged);
					}
				else
					{
					eventOnAllQueues = EFalse;
					}
				}
			}
		
		if(!eventOnAllQueues)
			{//another retry needed, but with increased time interval
			iRetrySpinner++;
			Retry(KRetryInitialDelay*iRetrySpinner);
			}
		}
	
	}

void CEventQueueRetry::Retry(TInt aDelay)
	{
	//the retry might be infinite, with an increasing interval, as delivery of the event is garuanteed
	//if aDelay is greater than max TInt, it will be negative number so we reset it to KRetryInitialDelay
	if(aDelay < 0)
		{
		aDelay = KRetryInitialDelay;
		}
	iTimer.After(iStatus, aDelay);
	SetActive();
	}

void CEventQueueRetry::Init(CScreen *aOwner)
	{
	iOwner = aOwner;
	iRetrySpinner = 0;
	
	}

void CEventQueueRetry::CancelRetry()
	{
	Cancel();
	}
