windowing/windowserver/nonnga/SERVER/POINTER.CPP
changeset 0 5d03bc08d59c
child 36 01a6848ebfd7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/POINTER.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,867 @@
+// 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:
+// Pointer functions
+// 
+//
+
+#include <e32std.h>
+#include <e32hal.h>
+#include "W32CLICK.H"
+#include "pointer.h"
+#include "rootwin.h"
+#include "windowgroup.h"
+#include "KEYCLICK.H"
+#include "ScrDev.H"
+#include "EVENT.H"
+#include "panics.h"
+#include "wstop.h"
+#include "inifile.h"
+#include "graphics/pointereventdata.h"
+
+TPoint WsPointer::iCurrentPos;
+TBool WsPointer::iPointerDown;
+const CWsWindow *WsPointer::iCurrentWindow;
+const CWsWindow *WsPointer::iActualWinPointerIsOver;
+const CWsWindow *WsPointer::iGrabWindow;
+const CWsWindow *WsPointer::iPrevClickWindow;
+TPoint WsPointer::iPrevClickPos;
+TTime WsPointer::iPrevClickTime;
+TPointerEvent::TType WsPointer::iPrevClickEventType;
+TTimeIntervalMicroSeconds32 WsPointer::iDoubleClickMaxInterval;
+TInt WsPointer::iDoubleClickMaxDistance;
+CWsPointerCursor *WsPointer::iCursorSprite;
+CWsPointerTimer *WsPointer::iRepeatTimer=NULL;
+TPointerCursorMode WsPointer::iPointerCursorMode=EPointerCursorNormal;
+CWsWindow *WsPointer::iRepeatWindow=NULL;
+TRect WsPointer::iRepeatRect;
+TXYInputType WsPointer::iXyInputType;
+TUint WsPointer::iLastUnmatchedDown1;
+TUint WsPointer::iLastUnmatchedDown2;
+TUint WsPointer::iLastUnmatchedDown3;
+TBool WsPointer::iTimerQueued;
+TBool WsPointer::iUpdateRequired;
+CPeriodic *WsPointer::iPeriodicTimer;
+CWsRootWindow* WsPointer::iRootWindow;
+
+TBool CWsPointerBuffer::iSignalled=EFalse;
+CWsPointerBuffer *CWsPointerBuffer::iCurrentBuffer=NULL;
+CCirBuf<TPoint> *CWsPointerBuffer::iPointerBuffer=NULL;
+TSglQue<CWsPointerBuffer> CWsPointerBuffer::iList(_FOFF(CWsPointerBuffer,iQue));
+
+void WsPointer::InitStaticsL()
+	{
+	iRepeatTimer=new(ELeave) CWsPointerTimer();
+	iRepeatTimer->ConstructL();
+	TMachineInfoV1Buf machineInfo;
+	UserHal::MachineInfo(machineInfo);
+	iXyInputType=machineInfo().iXYInputType;
+
+	iRootWindow = CWsTop::Screen()->RootWindow();
+
+	iCurrentWindow=MovesAvailable() ? iRootWindow : NULL;
+	iPeriodicTimer=CPeriodic::NewL(EPointerCursorPriority);
+	}
+
+void WsPointer::DeleteStatics()
+	{
+	SetPointerCursorMode(EPointerCursorNone);
+	UpdatePointerCursor();
+	delete iRepeatTimer;
+	delete iPeriodicTimer;
+	}
+
+void WsPointer::SetPointerCursorPos(TPoint aPos)
+	{
+	RestrictPos(aPos,EFalse);
+	iCurrentPos=aPos;
+	ReLogCurrentWindow();
+	UpdatePointerCursor();
+	}
+
+void WsPointer::SendEnterExitEvent(TEventCode aType)
+	{
+	if (iCurrentWindow
+		&& !(iCurrentWindow->PointerFilter()&EPointerFilterEnterExit)
+		&& !iCurrentWindow->ShutDownInProgress())
+		iCurrentWindow->QueueEvent(aType);
+	}
+
+void WsPointer::SetCurrentWindow(const CWsWindow *aWin)
+	{
+	if (aWin!=iCurrentWindow)
+		{
+		SendEnterExitEvent(EEventPointerExit);
+		iCurrentWindow=aWin;
+		SendEnterExitEvent(EEventPointerEnter);
+		}
+	}
+
+void WsPointer::ReLogCurrentWindow(TPoint &aPos, TPoint &aParentPos, const CWsWindowGroup *aForceInGroup)
+//
+// Relog the current pointer window, can be used to set a new iCurrentPos or when the window layout has changed.
+// Sets iCurrentPos to aPos and modifys aPos to the relative position within the new current window
+//
+	{
+	if (iRootWindow)
+		SetCurrentWindow(iRootWindow->PointerWindow(iCurrentPos,&aPos,&aParentPos,iGrabWindow,iActualWinPointerIsOver
+																										,aForceInGroup));
+	else
+		iCurrentWindow=NULL;
+	}
+
+void WsPointer::ReLogCurrentWindow()
+//
+// Relog the current pointer window when the window layout has changed.
+//
+	{
+	if (iCurrentWindow)	// NULL iCurrentWindow means pointer is up so don't relog it
+		SetCurrentWindow(iRootWindow->PointerWindow(iCurrentPos,NULL,NULL,iGrabWindow,iActualWinPointerIsOver,NULL));
+	}
+
+void WsPointer::ReLogWindow(const CWsWindow *aWin)
+//
+// Called when a window has changed it's filter state, will trigger a 'Enter' message if the window
+// is the current window
+//
+	{
+	if (aWin==iCurrentWindow)
+		SendEnterExitEvent(EEventPointerEnter);
+	}
+
+void WsPointer::UnmatchedDownPurged(TPointerEvent::TType aPointerType, TUint aHandle)
+	{
+	if (aPointerType==TPointerEvent::EButton1Up && iGrabWindow && iGrabWindow->ClientHandle()==aHandle)
+		{
+		if (iGrabWindow && iGrabWindow->ClientHandle()==aHandle)
+			iGrabWindow=NULL;
+		if (iRepeatWindow && iRepeatWindow->ClientHandle()==aHandle)
+			CancelPointerRepeatEventRequest();
+		}
+	switch(aPointerType)
+		{
+		case TPointerEvent::EButton1Up:
+			iLastUnmatchedDown1=aHandle;
+			break;
+		case TPointerEvent::EButton2Up:
+			iLastUnmatchedDown2=aHandle;
+			break;
+		case TPointerEvent::EButton3Up:
+			iLastUnmatchedDown3=aHandle;
+			break;
+		default:;
+		}
+	}
+
+void WsPointer::WindowDisconected(const CWsWindow *deletedWindow)
+	{
+	if (iRepeatWindow==deletedWindow)
+		CancelPointerRepeatEventRequest();
+	if (iGrabWindow==deletedWindow)
+		iGrabWindow=NULL;
+	if (iCurrentWindow==deletedWindow)
+		{
+		ReLogCurrentWindow();
+		UpdatePointerCursor();
+		}
+	}
+
+TEventQueueWalkRet RemovePointerUpFunc(TAny *aHandle, TWsEvent *aEvent)
+//
+// Callback function pointer for up event remove event queue walk
+//
+	{
+	if (aEvent->Type()==EEventPointer && aEvent->Pointer()->iType==TPointerEvent::EButton1Up && (*(TUint *)aHandle)==aEvent->Handle())
+		return(EEventQueueWalkDeleteEvent);
+	return(EEventQueueWalkOk);
+	}
+
+void WsPointer::ClaimGrab(const CWsWindow *aWindow,TBool aSendUpEvent)
+//
+// If the pointer is down claim grab in aWindow as though the down event had gone to this window
+// also send an up event to the window (if any) that would receive it the pointer was released now
+//
+	{
+	TInt modState=TWindowServerEvent::GetModifierState();
+	TWsEvent event;
+	TPointerEvent& pointerEvent=*event.Pointer();
+	pointerEvent.iModifiers=modState;
+	pointerEvent.iPosition=iCurrentPos;
+	if (iPointerDown)
+		{
+		if (iCurrentWindow!=aWindow)
+			{
+			if (aSendUpEvent)
+				ProcessEvent(TPointerEvent::EButton1Up,iCurrentPos,modState,NULL,EFalse);
+			else // If up event already in queue purge it
+				{
+				TUint handle=iCurrentWindow->ClientHandle();
+				iCurrentWindow->EventQueue()->WalkEventQueue(&RemovePointerUpFunc,&handle);
+				}
+			iPointerDown=ETrue;
+			if (aWindow->HasPointerGrab())
+				iGrabWindow=aWindow;
+			ReLogCurrentWindow(pointerEvent.iPosition,pointerEvent.iParentPosition,NULL);
+			pointerEvent.iType=TPointerEvent::EDrag;
+			ProcessPointerEvent(event);
+			}
+		}
+	else
+		{
+		const CWsWindow *current=iCurrentWindow;
+		iCurrentWindow=aWindow;
+		WS_ASSERT_DEBUG(iGrabWindow==NULL, EWsPanicPointerClaimGrab);
+		iGrabWindow=aWindow;	// Force the up event to be sent to aWindow
+		ReLogCurrentWindow(pointerEvent.iPosition,pointerEvent.iParentPosition,NULL);
+		pointerEvent.iType=TPointerEvent::EButton1Up;
+		ProcessPointerEvent(event);
+		iGrabWindow=NULL;
+		iCurrentWindow=current;
+		}
+	}
+
+TBool WsPointer::CheckDownEventPurged(TPointerEvent::TType aType)
+	{
+	switch(aType)
+		{
+		TUint lastUnmatchedDown;
+		case TPointerEvent::EButton1Up:
+			lastUnmatchedDown=iLastUnmatchedDown1;
+			iLastUnmatchedDown1=0;
+			goto lastUnmatchedDownCheck;
+		case TPointerEvent::EButton2Up:
+			lastUnmatchedDown=iLastUnmatchedDown2;
+			iLastUnmatchedDown2=0;
+			goto lastUnmatchedDownCheck;
+		case TPointerEvent::EButton3Up:
+			lastUnmatchedDown=iLastUnmatchedDown3;
+			iLastUnmatchedDown3=0;
+lastUnmatchedDownCheck:
+		if (lastUnmatchedDown==iCurrentWindow->ClientHandle())
+			return ETrue; // Don't deliver the event as we've already thrown away the down
+		default:		//Should never get to default
+			break;
+		}
+	return EFalse;
+	}
+
+TBool WsPointer::QueuePointerEvent(const CWsWindow *aWindow, TWsEvent &aEvent)
+	{
+	CWsClient *client=aWindow->WsOwner();
+	if (client)
+		{
+		CEventQueue *queue=aWindow->EventQueue();
+		aEvent.SetHandle(aWindow->ClientHandle());
+		if (aEvent.Handle()!=0)
+			{
+			if (aEvent.Pointer()->iType==TPointerEvent::EMove || aEvent.Pointer()->iType==TPointerEvent::EDrag)
+				{
+				queue->Wait();
+				const TWsEvent *prev=queue->PeekLastEvent();
+				if (prev!=NULL && prev->Type()==EEventPointer && prev->Handle()==aEvent.Handle() && prev->Pointer()->iType==aEvent.Pointer()->iType)
+					{
+					queue->UpdateLastEvent(aEvent);
+					return EFalse;
+					}
+				queue->Signal();
+				}
+			TWservEventPriorities priority=EEventPriorityLow;
+			switch (aEvent.Pointer()->iType)
+				{
+				case TPointerEvent::EButton1Up:
+				case TPointerEvent::EButton2Up:
+				case TPointerEvent::EButton3Up:
+					if (CheckDownEventPurged(aEvent.Pointer()->iType))
+						return ETrue;
+					if (queue->CheckRoom())
+						{
+						if (CheckDownEventPurged(aEvent.Pointer()->iType))
+							return ETrue;
+						} 
+					/*Fall Through if an event was not purged*/
+				case TPointerEvent::EButton1Down:
+				case TPointerEvent::EButton2Down:
+				case TPointerEvent::EButton3Down:
+					priority=EEventPriorityHigh;
+					break;
+				default:;
+				}
+			queue->QueueEvent(aEvent,priority);
+			}
+		}
+	return EFalse;
+	}
+
+void WsPointer::ProcessForegroundCheck()
+	{
+	CWsWindowGroup *group=iCurrentWindow->WinGroup();
+	if (group->iFlags&CWsWindowGroup::EGroupFlagAutoForeground)
+		group->SetOrdinalPosition(0);
+	}
+
+void WsPointer::ProcessPointerEvent(TWsEvent& aEvent)
+	{
+	if (iCurrentWindow && iCurrentWindow!=iRootWindow)
+		{
+		aEvent.SetType(EEventPointer);
+		aEvent.SetTimeNow();
+		TPointerEvent::TType type=aEvent.Pointer()->iType;
+		switch(type)
+			{
+			//TUint lastUnmatchedDown;
+			case TPointerEvent::EButton1Down:
+				ProcessForegroundCheck(); 
+				/*Fall Through*/
+			case TPointerEvent::EButton2Down:
+			case TPointerEvent::EButton3Down:
+				{
+				TPoint& pos=aEvent.Pointer()->iPosition;
+				if (iCurrentWindow==iPrevClickWindow &&
+					type==iPrevClickEventType &&
+					(Abs(pos.iX-iPrevClickPos.iX)+Abs(pos.iY-iPrevClickPos.iY))<iDoubleClickMaxDistance &&
+					aEvent.Time()<(iPrevClickTime+iDoubleClickMaxInterval))
+					{
+					aEvent.Pointer()->iModifiers|=EModifierDoubleClick;
+					iPrevClickWindow=NULL;	// Set to NULL to block a double double click
+					}
+				else
+					iPrevClickWindow=iCurrentWindow;
+				iPrevClickEventType=type;
+				iPrevClickPos=pos;
+				iPrevClickTime=aEvent.Time();
+				}
+				break;
+			default:
+				break;
+			}
+		if (iRepeatWindow)
+			{
+			if (PointerEventRepeatCheck(&aEvent, iCurrentWindow->ClientHandle()))
+				return;
+			CancelPointerRepeatEventRequest();
+			}
+		if (QueuePointerEvent(iCurrentWindow, aEvent))
+			return;
+		if (iCurrentWindow->DragDropCapture())
+			{
+			aEvent.SetType(EEventDragDrop);
+			QueuePointerEvent(iActualWinPointerIsOver, aEvent);
+			}
+		}
+	}
+
+TInt PointerTimerCallBack(TAny *)
+	{
+	WsPointer::TimerExpired();
+	return(KErrNone);
+	}
+
+void WsPointer::RestrictPos(TPoint& aPos,TBool aWithinDrawableArea/*=ETrue*/)
+	{
+	CScreen* screen = iRootWindow->Screen();
+	WS_ASSERT_DEBUG(screen->IsValidScreenSizeMode(screen->ScreenSizeMode()), EWsPanicInvalidScreenSizeMode);
+#if defined(__WINS__)
+	if (aWithinDrawableArea)
+		{
+		if (!DeltaMouse() && !TRect(screen->DrawableArea()).Contains(aPos))
+			{
+			return;			//Not in the drawable area so user may be trying to click on facia button.
+			}
+		}
+#endif
+	TRect validRect=screen->GetPointerCursorArea(screen->ScreenSizeMode());
+	if (aPos.iX<validRect.iTl.iX)
+		aPos.iX=validRect.iTl.iX;
+	else if (aPos.iX>=validRect.iBr.iX)
+		aPos.iX=validRect.iBr.iX-1;
+	if (aPos.iY<validRect.iTl.iY)
+		aPos.iY=validRect.iTl.iY;
+	else if (aPos.iY>=validRect.iBr.iY)
+		aPos.iY=validRect.iBr.iY-1;
+	}
+
+#if defined(__WINS__)
+TBool WsPointer::PreProcessEvent(TRawEvent &aRawEvent,TBool aFromHardware/*=EFlase*/)
+#else
+TBool WsPointer::PreProcessEvent(TRawEvent &aRawEvent)
+#endif
+	{
+#if defined(__WINS__)
+	WS_ASSERT_DEBUG(TRawEvent::EPointerMove==1, EWsPanicRawEventsTypeChanged);
+	WS_ASSERT_DEBUG(TRawEvent::EPointerMove+1==TRawEvent::EPointerSwitchOn, EWsPanicRawEventsTypeChanged);
+	WS_ASSERT_DEBUG(TRawEvent::EPointerSwitchOn+8==TRawEvent::EButton1Down, EWsPanicRawEventsTypeChanged);
+	WS_ASSERT_DEBUG(TRawEvent::EButton1Down+5==TRawEvent::EButton3Up, EWsPanicRawEventsTypeChanged);
+#endif
+	TRawEvent::TType type=aRawEvent.Type();
+	if (type<TRawEvent::EPointerMove || (type>TRawEvent::EPointerSwitchOn && type<TRawEvent::EButton1Down)
+																						|| type>TRawEvent::EButton3Up)
+		return ETrue;
+	if (!XyInput())
+		return EFalse;
+	TPoint xy=aRawEvent.Pos();
+	if (DeltaMouse())
+		{
+	#if defined(__WINS__)
+		if (aFromHardware)
+			return EFalse;
+	#endif
+		if (type==TRawEvent::EPointerMove)
+			{
+			xy+=iCurrentPos;
+			RestrictPos(xy);
+			}
+		else
+			xy=iCurrentPos;
+		}
+	else
+		{
+		CScreen* screen=iRootWindow->Screen();
+	#if !defined(__WINS__)
+		TSize screenSize=screen->ScreenDevice()->SizeInPixels()-TSize(1,1);             //This is in the current rotation
+		switch (screen->Orientation())
+			{
+			case CFbsBitGc::EGraphicsOrientationRotated90:
+				xy.SetXY(xy.iY,screenSize.iHeight-xy.iX);
+				break;
+			case CFbsBitGc::EGraphicsOrientationRotated180:
+				xy=-(xy-screenSize);
+				break;
+			case CFbsBitGc::EGraphicsOrientationRotated270:
+				xy.SetXY(screenSize.iWidth-xy.iY,xy.iX);
+				break;
+			default:;		//To stop warning
+			}
+	#endif
+		// Move the raw event position by shifting it by Origin and scale
+		xy=screen->PhysicalToLogical(xy);
+		RestrictPos(xy);
+		}
+	aRawEvent.Set(type,xy.iX,xy.iY);
+	return ETrue;
+	}
+
+void WsPointer::ProcessEvent(TPointerEvent::TType aType, const TPoint &aPos, TUint aModifiers
+																				,const CWsWindowGroup *aForceInGroup,TBool aNatural)
+	{
+	iCurrentPos=aPos;
+	if (aType==TPointerEvent::EMove && !MovesAvailable() && !iPointerDown)
+		return;
+	TPoint pos(iCurrentPos);	// We need a non-const TPoint for 'ReLogCurrentWindow'
+	TPoint parPos;
+	ReLogCurrentWindow(pos,parPos,aForceInGroup);
+	TWsEvent event;
+	TPointerEvent& pointerEvent=*event.Pointer();
+	pointerEvent.iModifiers=aModifiers;
+	pointerEvent.iPosition=pos;
+	pointerEvent.iParentPosition=parPos;
+	switch(aType)
+		{
+		case TPointerEvent::EButton1Down:
+			iPointerDown=ETrue;
+			if (iGrabWindow==NULL && iCurrentWindow->HasPointerGrab())
+				iGrabWindow=iCurrentWindow;
+			if (!MovesAvailable() && iCurrentWindow->PointerFilter()&EPointerGenerateSimulatedMove)
+				{
+				pointerEvent.iType=TPointerEvent::EMove;
+				ProcessEvent(event);
+				}
+			break;
+		case TPointerEvent::EButton1Up:
+			iPointerDown=EFalse;
+			iGrabWindow=NULL;
+			break;
+		case TPointerEvent::EMove:
+			if (iPointerDown)
+				aType=TPointerEvent::EDrag;
+			break;
+		default:;
+		}
+	pointerEvent.iType=aType;
+	if (aNatural && CClick::IsHandler())
+		{
+		CClick::PointerEvent(iCurrentPos,pointerEvent);
+		TPointerEventData params;
+		params.iVersion=0;
+		params.iCurrentPos=iCurrentPos;
+		params.iPointerEvent.iType 		= pointerEvent.iType;
+		params.iPointerEvent.iModifiers = pointerEvent.iModifiers;
+		params.iPointerEvent.iPosition  = pointerEvent.iPosition;
+		params.iPointerEvent.iParentPosition = pointerEvent.iParentPosition;
+		params.iClientHandle=iCurrentWindow->ClientHandle();
+		params.iWindowOrigin=iCurrentWindow->Origin();
+		CWsWindowGroup* groupWin=iCurrentWindow->WinGroup();
+		params.iWindowGroupId=groupWin ? groupWin->Identifier() : 0;
+		params.iSource=TPointerEventData::EUnspecified;
+		CClick::OtherEvent(EEventPointer,&params);
+		}
+	ProcessEvent(event);
+	}
+
+void WsPointer::ProcessEvent(TWsEvent& aEvent)
+	{
+	TUint filter=iCurrentWindow->PointerFilter();
+	TPointerEvent::TType type=aEvent.Pointer()->iType;
+	if ((type!=TPointerEvent::EMove || !(filter&EPointerFilterMove)) &&
+		 (type!=TPointerEvent::EDrag || !(filter&EPointerFilterDrag)))
+		{
+		TPoint pos=aEvent.Pointer()->iPosition;
+		if ((type==TPointerEvent::EMove || type==TPointerEvent::EDrag) && iCurrentWindow->UsingPointerBuffer())
+			CWsPointerBuffer::PointerEvent((CWsClientWindow *)iCurrentWindow,pos);
+		else if (!WsKeyboardEmulator::PointerEvent(type,pos,iCurrentWindow->PointerKeyList()))
+			ProcessPointerEvent(aEvent);
+		}
+	if (!MovesAvailable() && (type==TPointerEvent::EButton1Up || type==TPointerEvent::ESwitchOn))
+		iCurrentWindow=NULL;
+	PointerCursorUpdateCheck();
+	}
+
+void WsPointer::TimerExpired()
+	{
+	WS_ASSERT_DEBUG(iTimerQueued, EWsPanicPointerTimer);
+	if (iUpdateRequired)
+		{
+		UpdatePointerCursor();
+		iUpdateRequired=EFalse;
+		}
+	else
+		{
+		iTimerQueued=EFalse;
+		iPeriodicTimer->Cancel();
+		}
+	}
+
+void WsPointer::GetDoubleClickSettings(TTimeIntervalMicroSeconds32 &aTime, TInt &aDistance)
+	{
+	aTime=iDoubleClickMaxInterval;
+	aDistance=iDoubleClickMaxDistance;
+	}
+
+void WsPointer::SetDoubleClick(const TTimeIntervalMicroSeconds32 &aTime, TInt aDistance)
+	{
+	iDoubleClickMaxInterval=aTime;
+	iDoubleClickMaxDistance=aDistance;
+	}
+
+void WsPointer::PointerCursorUpdateCheck()
+	{
+	CWsPointerCursor *sprite=CalculatePointerCursor();
+	if (iCursorSprite || sprite)	// If there either was, or is a pointer cursor we need an update
+		{
+		if (!iTimerQueued)
+			{
+			UpdatePointerCursorTo(sprite);
+			iPeriodicTimer->Start(TTimeIntervalMicroSeconds32(EPointerUpdateGapInMicroSeconds),
+									TTimeIntervalMicroSeconds32(EPointerUpdateGapInMicroSeconds),
+									  TCallBack(PointerTimerCallBack,NULL));
+			iTimerQueued=ETrue;
+			}
+		else
+			iUpdateRequired=ETrue;
+		}
+	}
+
+void WsPointer::UpdatePointerCursor()
+	{
+//__PROFILE_START(3);
+	CWsPointerCursor *sprite=CalculatePointerCursor();
+	UpdatePointerCursorTo(sprite);
+//__PROFILE_END(3);
+	}
+
+void WsPointer::UpdatePointerCursorTo(CWsPointerCursor* aNewCursor)
+	{
+	CScreen* screen=NULL;
+	if (iCursorSprite!=aNewCursor)
+		{
+		if (iCursorSprite)
+			{
+			iCursorSprite->Deactivate();
+			screen=iCursorSprite->Screen();		//This will need changing ##
+			}
+		iCursorSprite=aNewCursor;
+		if (iCursorSprite)
+			{
+			iCursorSprite->SetPos(iCurrentPos);
+			iCursorSprite->Activate();
+			}
+		goto Update;
+		}
+	else if (iCursorSprite)
+		{
+		iCursorSprite->SetPos(iCurrentPos);
+	Update:
+		if (!screen)
+			screen=iCursorSprite->Screen();
+		screen->Update();
+		}
+	}
+
+CWsPointerCursor* WsPointer::CalculatePointerCursor()
+	{
+	CWsPointerCursor *sprite=NULL;
+	if (iCurrentWindow && (iPointerCursorMode==EPointerCursorNormal || iPointerCursorMode==EPointerCursorWindow))
+		{
+		const CWsWindowBase* window=iCurrentWindow;
+		do	{
+			sprite=window->PointerCursor();
+			if (window->WinType()!=EWinTypeClient)
+				break;
+			window=window->BaseParent();
+			} while (!sprite);
+		}
+	if (!sprite && iCurrentWindow && (iPointerCursorMode==EPointerCursorFixed || iPointerCursorMode==EPointerCursorNormal))
+		sprite=CWsClient::DefaultSystemPointerCursor();
+	return sprite;
+	}
+
+TEventQueueWalkRet PointerRepeatPurgeFunc(TAny *, TWsEvent *aEvent)
+//
+// Callback function for event queue walk
+//
+	{
+	return(WsPointer::PointerRepeatPurgeCheck(aEvent));
+	}
+
+TBool WsPointer::PointerEventRepeatCheck(const TWsEvent *aEvent, TUint32 aHandle)
+//
+// Return ETrue if this pointer event is consumed by the pointer repeat
+//
+	{
+	TPointerEvent *pntEvent=aEvent->Pointer();
+	if (aHandle==iRepeatWindow->ClientHandle() && 
+		 (pntEvent->iType==TPointerEvent::EDrag || pntEvent->iType==TPointerEvent::EMove) &&
+		  iRepeatRect.Contains(pntEvent->iPosition))
+		return(ETrue);
+	return(EFalse);
+	}
+
+TEventQueueWalkRet WsPointer::PointerRepeatPurgeCheck(const TWsEvent *aEvent)
+	{
+	if (iRepeatWindow && aEvent->Type()==EEventPointer)
+		{
+		if (PointerEventRepeatCheck(aEvent,aEvent->Handle()))
+			return(EEventQueueWalkDeleteEvent);	// Purge the event as it is a move/drag within the repeat rect
+		CancelPointerRepeatEventRequest();
+		}
+	return(EEventQueueWalkOk);
+	}
+
+void WsPointer::RequestPointerRepeatEvent(CWsWindow *aWindow, TTimeIntervalMicroSeconds32 aTime,const TRect &aRect)
+	{
+	CancelPointerRepeatEventRequest();
+	iRepeatWindow=aWindow;
+	iRepeatRect=aRect;
+	iRepeatTimer->After(aTime);
+	aWindow->EventQueue()->WalkEventQueue(&PointerRepeatPurgeFunc,NULL);
+	if (iRepeatWindow && !iRepeatRect.Contains(iCurrentPos-iRepeatWindow->Origin()))
+		CancelPointerRepeatEventRequest();
+	}
+
+void WsPointer::CancelPointerRepeatEventRequest()
+	{
+	if (iRepeatWindow)
+		{
+		iRepeatWindow=NULL;
+		iRepeatTimer->Cancel();
+		}
+	}
+
+void WsPointer::RepeatTimerCompleted()
+	{
+	TWsEvent event;
+	event.SetType(EEventPointer);
+	event.SetTimeNow();
+	event.Pointer()->iModifiers=TWindowServerEvent::GetModifierState();
+	event.Pointer()->iPosition=iCurrentPos-iRepeatWindow->Origin();
+	event.Pointer()->iParentPosition=iCurrentPos-iRepeatWindow->BaseParent()->Origin();
+	event.Pointer()->iType=TPointerEvent::EButtonRepeat;
+	QueuePointerEvent(iRepeatWindow, event);
+	iRepeatWindow=NULL;
+	}
+
+#if defined(__WINS__)
+void WsPointer::SetXyInputType(TXYInputType aXyInputType)
+	{
+	if (iXyInputType>EXYInputPointer && aXyInputType<EXYInputMouse && !iPointerDown)
+		{
+		iCurrentWindow=NULL;
+		UpdatePointerCursor();
+		}
+	else if (iXyInputType<EXYInputMouse && aXyInputType>EXYInputPointer && !iPointerDown)
+		{
+		TPoint pos(iCurrentPos);
+		TPoint parPos;
+		ReLogCurrentWindow(pos,parPos,NULL);
+		UpdatePointerCursor();
+		}
+	iXyInputType=aXyInputType;
+	}
+#endif
+
+//
+
+CWsPointerTimer::CWsPointerTimer() : CTimer(EPointerRepeatPriority)
+	{}
+
+void CWsPointerTimer::ConstructL()
+	{
+	CTimer::ConstructL();
+	CActiveScheduler::Add(this);
+	}
+
+void CWsPointerTimer::RunL()
+	{
+	User::ResetInactivityTime();
+	WS_ASSERT_DEBUG(iStatus.Int()==KErrNone, EWsPanicPointerRepeatTimerStatus);
+	WsPointer::RepeatTimerCompleted();
+	}
+
+//
+
+CWsPointerBuffer::~CWsPointerBuffer()
+	{
+	if (this == iCurrentBuffer)
+		{
+		// We're about to be destroyed - don't want to be pointed at any more.
+		iCurrentBuffer = NULL;
+		}
+	iList.Remove(*this);
+	}
+
+void CWsPointerBuffer::ConnectL(CWsClientWindow *aWindow, TInt aMaxPoints, TUint aFlags)
+	{
+	CWsPointerBuffer *pb=NULL;
+	for(TSglQueIter<CWsPointerBuffer> iter(iList);(pb=iter++)!=NULL;)
+		if (pb->iWindow==aWindow)
+			User::Leave(KErrInUse);
+	CWsPointerBuffer *pbuf=new(ELeave) CWsPointerBuffer;
+	pbuf->iWindow=aWindow;
+	pbuf->iMaxPoints=aMaxPoints;
+	pbuf->iFlags=aFlags;
+	iList.AddFirst(*pbuf);
+	CleanupStack::PushL(pbuf);
+	AdjustMaxSizeL();
+	CleanupStack::Pop();
+	}
+
+void CWsPointerBuffer::Disconnect(CWsClientWindow *aWindow)
+	{
+	CWsPointerBuffer *pb=NULL;
+	for(TSglQueIter<CWsPointerBuffer> iter(iList);(pb=iter++)!=NULL;)
+		{
+		if (pb->iWindow==aWindow)
+			{
+			delete pb; // Note that the destructor also sets iCurrentBuffer to NULL if it is pointing at pb
+			TRAP_IGNORE(AdjustMaxSizeL());	// Shouldn't fail, but doesn't matter if it does as we simply have a larger buffer than needed
+			break; // from for loop
+			}
+		}
+	}
+
+void CWsPointerBuffer::Reset()
+	{
+	iSignalled=EFalse;
+	iPointerBuffer->Reset();
+	}
+
+void CWsPointerBuffer::SignalBufferReady()
+	{
+	if (!iSignalled)
+		if (iCurrentBuffer && iCurrentBuffer->iWindow->QueueEvent(EEventPointerBufferReady))
+			iSignalled=ETrue;
+	}
+
+void CWsPointerBuffer::PointerEvent(CWsClientWindow *aWindow,const TPoint &aPoint)
+	{
+	if (iCurrentBuffer==NULL || aWindow!=iCurrentBuffer->iWindow)
+		{
+		Reset();
+		CWsPointerBuffer *pb=NULL;
+		for(TSglQueIter<CWsPointerBuffer> iter(iList);(pb=iter++)!=NULL;)
+			{
+			if (pb->iWindow==aWindow)
+				{
+				iCurrentBuffer=pb;
+				break; // from for loop
+				}
+			}
+		}
+	iPointerBuffer->Add(&aPoint);
+	SignalBufferReady();
+	}
+
+void CWsPointerBuffer::RetrievePointerMoveBuffer(CWsClientWindow *aWindow,TInt aMaxPoints)
+	{
+	enum {KPointerMoveBufferSize=32};	// Puts 256 bytes on the stack
+	if (iCurrentBuffer && aWindow==iCurrentBuffer->iWindow)
+		{
+		iSignalled=EFalse;
+		TInt max=Min(aMaxPoints,iPointerBuffer->Count());
+		TInt buflen=0;
+		aWindow->WsOwner()->SetReply(max);
+		TPoint point;
+		TBuf8<KPointerMoveBufferSize*sizeof(TPoint)> pnts;
+		for(TInt index=0;index<max;index++)
+			{
+			iPointerBuffer->Remove(&point);
+			pnts.Append((TUint8 *)&point,sizeof(TPoint));
+			buflen++;
+			if (buflen==KPointerMoveBufferSize)
+				{
+				CWsClient::ReplyBuf(pnts);
+				pnts.Zero();
+				buflen=0;
+				}
+			}
+		if (buflen>0)
+			CWsClient::ReplyBuf(pnts);
+		if (iPointerBuffer->Count())
+			SignalBufferReady();
+		}
+	}
+
+void CWsPointerBuffer::DiscardPointerMoveBuffer(TUint aHandle)
+	{
+	if (iCurrentBuffer && aHandle==iCurrentBuffer->iWindow->ClientHandle())
+		Reset();
+	}
+
+void CWsPointerBuffer::DiscardPointerMoveBuffer(CWsClientWindow *aWindow)
+	{
+	if (iCurrentBuffer && aWindow==iCurrentBuffer->iWindow)
+		Reset();
+	}
+
+void CWsPointerBuffer::AdjustMaxSizeL()
+	{
+	TInt max=0;
+	CWsPointerBuffer *pb=NULL;
+	for(TSglQueIter<CWsPointerBuffer> iter(iList);(pb=iter++)!=NULL;)
+		if (pb->iMaxPoints>max)
+			max=pb->iMaxPoints;
+	if (max==0)
+		{
+		delete iPointerBuffer;
+		iPointerBuffer=NULL;
+		}
+	else if (!iPointerBuffer)
+		{
+		CCirBuf<TPoint> *pointerBuffer=new(ELeave) CCirBuf<TPoint>;
+		CleanupStack::PushL(pointerBuffer);
+		pointerBuffer->SetLengthL(max);
+		CleanupStack::Pop();
+		iPointerBuffer=pointerBuffer;
+		}
+	else
+		iPointerBuffer->SetLengthL(max);
+	}