diff -r 000000000000 -r 5d03bc08d59c windowing/windowserver/nonnga/SERVER/POINTER.CPP --- /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 +#include +#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 *CWsPointerBuffer::iPointerBuffer=NULL; +TSglQue 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))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.iBr.iX) + aPos.iX=validRect.iBr.iX-1; + 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 (typeTRawEvent::EPointerSwitchOn && typeTRawEvent::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,¶ms); + } + 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 && aXyInputTypeEXYInputPointer && !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 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 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 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 pnts; + for(TInt index=0;indexRemove(&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 iter(iList);(pb=iter++)!=NULL;) + if (pb->iMaxPoints>max) + max=pb->iMaxPoints; + if (max==0) + { + delete iPointerBuffer; + iPointerBuffer=NULL; + } + else if (!iPointerBuffer) + { + CCirBuf *pointerBuffer=new(ELeave) CCirBuf; + CleanupStack::PushL(pointerBuffer); + pointerBuffer->SetLengthL(max); + CleanupStack::Pop(); + iPointerBuffer=pointerBuffer; + } + else + iPointerBuffer->SetLengthL(max); + }