windowing/windowserver/nga/SERVER/TCURSOR.CPP
changeset 0 5d03bc08d59c
child 11 fed1595b188e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/SERVER/TCURSOR.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,579 @@
+// 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:
+// The text cursor
+// 
+//
+
+#include <e32std.h>
+#include <graphics/wscursor.h>
+#include "server.h"
+#include "tcursor.h"
+#include "windowgroup.h"
+#include "wstop.h"
+#include "panics.h"
+#include "EVENT.H"
+#include "graphics/windowserverconstants.h"
+
+static const TInt64 KFlashRate(500000); // duration cursor is ON or OFF
+
+void RWsTextCursor::ConstructL(CWsWindowGroup *aGroupWin)
+	{
+	iInternalFlags = 0;
+	iGroupWin=aGroupWin;
+	iCustomTextCursor = NULL;
+	}
+
+void RWsTextCursor::Close()
+	{
+	iDrawRegion.Close();
+	Cancel();
+	}
+
+void RWsTextCursor::SetL(const TWsWinCmdSetTextCursor &aSet, TBool aClipped)
+	{
+	if (aSet.cursor.iType < TTextCursor::ETypeFirst ||
+	        (aSet.cursor.iType > TTextCursor::ETypeLast &&
+		 aSet.cursor.iType <= TTextCursor::ETypeLastBasic) ||
+		(aSet.cursor.iFlags&static_cast<TUint>(ETextCursorPrivateFlags)))
+		{
+		Cancel();
+		iGroupWin->OwnerPanic(EWservPanicInvalidTextCursor);
+		}
+	else
+		{
+		CWsClientWindow* win = NULL;
+		iGroupWin->WsOwner()->HandleToClientWindow(aSet.window, &win);
+
+		// Check window is a child of the group window
+		CWsWindowBase* searchWin = NULL;
+		for(searchWin=win; searchWin->WinType()!=EWinTypeGroup; searchWin=searchWin->BaseParent())
+			{}
+		if (iGroupWin != searchWin)
+			{
+			Cancel();
+			iGroupWin->OwnerPanic(EWservPanicWindow);
+			}
+
+		TPoint pos(aSet.pos.iX, aSet.pos.iY-aSet.cursor.iAscent);
+		TSize size(aSet.cursor.iWidth, aSet.cursor.iHeight);
+		TUint flags = aSet.cursor.iFlags;
+		TInt type = aSet.cursor.iType;
+		TRect clipRect = iClipRect;
+		TRgb color = aSet.cursor.iColor;
+		CWsCustomTextCursor* customTextCursor = iCustomTextCursor;
+		TBool changed = EFalse;
+
+		TPoint clipOrigo;
+		TSize clipSize;
+
+		if (type > TTextCursor::ETypeLastBasic)
+			{
+			changed = ETrue;
+
+			customTextCursor = CWsClient::FindCustomTextCursor(type);
+			if (!customTextCursor)
+				{
+				Cancel();
+				iGroupWin->OwnerPanic(EWservPanicNoCustomTextCursor);
+				return;
+				}
+			
+			if( !customTextCursor->HasSpriteMember() )
+				{
+				iGroupWin->OwnerPanic(EWservPanicNoSpriteMember);
+				return;
+				}
+			
+			TInt yAdjust=0;
+			switch (customTextCursor->Alignment())
+				{
+				case RWsSession::ECustomTextCursorAlignTop:
+					break;
+				case RWsSession::ECustomTextCursorAlignBaseline:
+					yAdjust = aSet.cursor.iAscent-1;
+					break;
+				case RWsSession::ECustomTextCursorAlignBottom:
+					yAdjust = aSet.cursor.iHeight-1;
+					break;
+				default:
+					Cancel();
+					iGroupWin->OwnerPanic(EWservPanicCustomTextCursorAlign);
+					return;
+				}
+			pos.iY += yAdjust;
+			// Start with a clipping rect to be the whole window
+			// relative cursor pos and shrink down to what we want
+			clipOrigo = -pos;
+			clipSize = win->Size();
+			if (flags & TTextCursor::EFlagClipHorizontal)
+				{
+				clipOrigo.iX = 0;
+				clipSize.iWidth = size.iWidth;
+				}
+			if (flags & TTextCursor::EFlagClipVertical)
+				{
+				clipOrigo.iY = -yAdjust;
+				clipSize.iHeight = aSet.cursor.iHeight;
+				}
+			}
+		else
+			{
+			customTextCursor = NULL;
+			}
+
+		if (aClipped)
+			{
+			flags|=ETextCursorFlagClipped;
+			clipRect=aSet.rect;
+			}
+
+		if (pos != iPos || size != iSize || iType != type ||
+			flags != iFlags || clipRect != iClipRect || color != iColor ||
+			customTextCursor != iCustomTextCursor || win != iWin)
+			{
+			// There is a change in the cursor.
+			changed = ETrue;
+			}
+
+		if (iInternalFlags&EHasFocus && changed)
+			{
+			if ((win != iWin && !iCustomTextCursor) || (customTextCursor && !iCustomTextCursor))
+				ReleaseNode();
+			TCursorSprite::Hide();
+			}
+
+		UpdateAttributes(pos, size, type, flags, clipRect, color, customTextCursor, win);
+
+		if (customTextCursor && iInternalFlags&EHasFocus)
+			{
+			customTextCursor->CompleteL(win, !(flags&TTextCursor::EFlagNoFlash), flags & (TTextCursor::EFlagClipHorizontal | TTextCursor::EFlagClipVertical), clipOrigo, clipSize);
+			customTextCursor->SetPositionNoRedraw(pos);
+			}
+
+		if (iInternalFlags&EHasFocus && changed)
+			{
+			TCursorSprite::SetCurrentCursor(this, win);
+			}
+		}
+	}
+void RWsTextCursor::UpdateAttributes(TPoint aPos, TSize aSize, TInt aType, TUint aFlags, TRect aClipRect, TRgb aColor, CWsCustomTextCursor* aCustomTextCursor, CWsClientWindow* aWin)
+	{
+	if (aPos != iPos || aSize != iSize)
+		{
+		iPos = aPos;
+		iSize = aSize;
+		WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen);
+		MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver();
+		if (windowTreeObserver && iInternalFlags&EHasFocus && iInternalFlags&EActiveNode)
+			windowTreeObserver->NodeExtentChanged(*this, RectRelativeToScreen());
+		}
+
+	if (aType != iType)
+		{
+		iType = aType;
+		NotifyObserver(MWsWindowTreeObserver::ECursorType);
+		}
+
+	if (aClipRect != iClipRect)
+		{
+		iClipRect = aClipRect; // must update clip rect before sending clip rect set/unset notification
+		if ((aFlags&ETextCursorFlagClipped) && (iFlags&ETextCursorFlagClipped))
+			NotifyObserver(MWsWindowTreeObserver::ECursorClipRect); // clip rect changed
+		}
+
+	if (aFlags != iFlags)
+		{
+		TBool sendFlagChanged = EFalse;
+		if ((aFlags&ETextCursorFlagClipped) != (iFlags&ETextCursorFlagClipped))
+			{
+			if (iInternalFlags&EHasFocus && iInternalFlags&EActiveNode)
+				{
+				// We can't send flag changed till iFlags has been updated, as otherwise plugins responding to
+				// the flag changed notification by calling ClipRect() may get the wrong rect
+				sendFlagChanged = ETrue;
+				}
+			}
+		const TBool userFlagsChanged((aFlags&ETextCursorUserFlags) != (iFlags&ETextCursorUserFlags)); 
+		iFlags = aFlags;
+		if (userFlagsChanged)
+			NotifyObserver(MWsWindowTreeObserver::ECursorFlags);
+		if (sendFlagChanged)
+			{
+			WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen);
+			MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver();
+			if (windowTreeObserver)
+				windowTreeObserver->FlagChanged(*this, MWsWindowTreeObserver::ECursorClipRectSet, !!(iFlags&ETextCursorFlagClipped)); // clip rect set/unset
+			}
+		}
+
+	if (aColor != iColor)
+		{
+		iColor = aColor;
+		NotifyObserver(MWsWindowTreeObserver::ECursorColor);
+		}
+	iCustomTextCursor = aCustomTextCursor;
+	iWin = aWin;
+	}
+
+void RWsTextCursor::NotifyObserver(MWsWindowTreeObserver::TAttributes aAttribute) const
+	{
+	if (iInternalFlags&EHasFocus && iInternalFlags&EActiveNode)
+		{
+		WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen);
+		MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver();
+		if (windowTreeObserver)
+			windowTreeObserver->AttributeChanged(*this, aAttribute);
+		}
+	}
+
+void RWsTextCursor::CreateNode()
+	{
+	WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen);
+	MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver();
+	if (windowTreeObserver && !(iInternalFlags&EActiveNode))
+		{
+		iInternalFlags |= EActiveNode;
+		windowTreeObserver->NodeCreated(*this, iWin);
+		windowTreeObserver->NodeExtentChanged(*this, RectRelativeToScreen());
+		if (iFlags&ETextCursorFlagClipped)
+			windowTreeObserver->FlagChanged(*this, MWsWindowTreeObserver::ECursorClipRectSet, ETrue);
+		windowTreeObserver->NodeActivated(*this);
+		}
+	}
+
+void RWsTextCursor::ReleaseNode()
+	{
+	if (iInternalFlags&EActiveNode)
+		{
+		WS_ASSERT_DEBUG(iGroupWin->Screen(),EWsPanicNoScreen);
+		MWsWindowTreeObserver* const windowTreeObserver = iGroupWin->Screen()->WindowTreeObserver();
+		if (windowTreeObserver)
+			{
+			windowTreeObserver->NodeReleased(*this);
+			iInternalFlags &= ~EActiveNode;
+			}
+		}
+	}
+
+void RWsTextCursor::SendState(MWsWindowTreeObserver& aWindowTreeObserver) const
+	{
+	if (iInternalFlags & EActiveNode)
+		{
+		aWindowTreeObserver.NodeCreated(*this, iWin);
+		aWindowTreeObserver.NodeExtentChanged(*this, RectRelativeToScreen());
+		if (iFlags&ETextCursorFlagClipped)
+			aWindowTreeObserver.FlagChanged(*this, MWsWindowTreeObserver::ECursorClipRectSet, ETrue);
+		aWindowTreeObserver.NodeActivated(*this);
+		}
+	}
+
+void RWsTextCursor::Cancel()
+	{
+	if (iType!=TTextCursor::ETypeNone)
+		{
+		if (iInternalFlags&EHasFocus)
+			TCursorSprite::SetFocus(NULL);
+		iType=TTextCursor::ETypeNone;
+		iWin=NULL;
+		}
+	}
+
+void RWsTextCursor::Disable()
+	{
+	if (iWin)
+		{
+		TCursorSprite::Hide();
+		}
+	}
+
+void RWsTextCursor::Enable()
+	{
+	if (iWin)
+		{
+		TCursorSprite::Reveal();
+		}
+	}
+
+void RWsTextCursor::LostFocus()
+	{
+	TCursorSprite::SetFocus(NULL);
+	iInternalFlags &= ~EHasFocus;
+	}
+
+void RWsTextCursor::ReceivedFocus()
+	{
+	iInternalFlags |= EHasFocus;
+	if (iType!=TTextCursor::ETypeNone && iWin)
+		{
+		TCursorSprite::SetFocus(this,iWin);
+		if (iCustomTextCursor)
+			{
+			iCustomTextCursor->SetPositionNoRedraw(iPos);
+			}
+		}
+	}
+
+TRect RWsTextCursor::RectRelativeToScreen() const
+	{
+	TRect rect;
+	rect.iTl=iPos+iWin->Origin();
+	rect.iBr=rect.iTl+iSize;
+	return(rect);
+	}
+
+TRect RWsTextCursor::RectRelativeToWindow() const
+	{
+	TRect rect;
+	rect.iTl=iPos;
+	rect.iBr=rect.iTl+iSize;
+	return rect;
+	}
+
+void RWsTextCursor::doDraw(const TRegion& aRegion)
+	{
+	TRegionFix<1> fallbackClipRegion;
+	const TRegion *clipRegion= &aRegion;
+	if (aRegion.CheckError())
+		{
+		fallbackClipRegion.AddRect(iWin->AbsRect());
+		clipRegion= &fallbackClipRegion;
+		}
+
+	if(!clipRegion->IsEmpty())
+		{
+		MWsTextCursor::TTextCursorInfo renderStageCursorInfo(
+			RectRelativeToWindow(),
+			*clipRegion,
+			iType, static_cast<MWsWindow *>(Win()), iColor
+			);
+		
+		MWsTextCursor* textCursor = iWin->Screen()->RenderStageTextCursor();
+
+		textCursor->DrawTextCursor(renderStageCursorInfo);
+
+		TWindowServerEvent::NotifyScreenDrawingEvent(clipRegion);
+		}
+	}
+
+void RWsTextCursor::Draw(const TRegion& aRegion)
+	{
+	iDrawRegion.Copy(iWin->VisibleRegion());
+	if (iFlags&ETextCursorFlagClipped)
+		{
+		TRect rect(iClipRect);
+		rect.Move(iWin->Origin());
+		iDrawRegion.ClipRect(rect);
+		}
+
+	// Need to clip against a possible recent screen size change.
+	iDrawRegion.ClipRect(iWin->Screen()->SizeInPixels());
+
+	RWsRegion tmpRegion;
+	tmpRegion.Intersection(iDrawRegion, aRegion);
+	if (tmpRegion.CheckError())
+		doDraw(iDrawRegion);
+	else
+		{
+		if (!tmpRegion.IsEmpty())
+			{
+			doDraw(tmpRegion);
+			}
+		}
+	tmpRegion.Close();
+	}
+
+void RWsTextCursor::WindowDisconnected(CWsWindow *aWindow)
+	{
+	if (iWin==aWindow)
+		Cancel();
+	}
+
+TBool RWsTextCursor::IsStandardCursorActive()
+	{
+	return TCursorSprite::IsStandardCursorActive();
+	}
+
+TBool RWsTextCursor::IsFlashing() const
+	{
+	return !(iFlags&TTextCursor::EFlagNoFlash);
+	}
+
+void RWsTextCursor::ScheduleReDrawNow()
+	{
+	if (!iGroupWin->Screen()->ChangeTracking())
+		iGroupWin->Screen()->ScheduleAnimation(ETextCursor, RectRelativeToScreen(), 0, 0, 0, iWin);
+	}
+
+/** @see MWsWindowTreeNode */
+MWsWindowTreeNode::TType RWsTextCursor::NodeType() const
+	{
+	return MWsWindowTreeNode::EWinTreeNodeStandardTextCursor; 
+	}
+
+/** @see MWsWindowTreeNode */
+const MWsWindow* RWsTextCursor::Window() const
+	{
+	return NULL;
+	}
+
+/** @see MWsWindowTreeNode */
+const MWsSprite* RWsTextCursor::Sprite() const
+	{
+	return NULL;
+	}
+
+/** @see MWsWindowTreeNode */
+const MWsStandardTextCursor* RWsTextCursor::StandardTextCursor() const
+	{
+	return this;
+	}
+
+/** @see MWsWindowTreeNode */
+const MWsWindowGroup* RWsTextCursor::WindowGroup() const
+	{
+	return static_cast<MWsWindowGroup*>(iGroupWin);
+	}
+
+/** @see MWsWindowTreeNode */
+const MWsWindowTreeNode* RWsTextCursor::ParentNode() const
+	{
+	return iWin;
+	}
+
+/** @see MWsStandardTextCursor */
+TInt RWsTextCursor::Type() const
+	{
+	return iType;
+	}
+
+/** @see MWsStandardTextCursor */
+TRect RWsTextCursor::Rect() const
+	{
+	return RectRelativeToScreen();
+	}
+
+/** @see MWsStandardTextCursor */
+TRect RWsTextCursor::ClipRect() const
+	{
+	if (iFlags&ETextCursorFlagClipped)
+		{
+		TRect clipRectRelativeToScreen(iClipRect);
+		clipRectRelativeToScreen.Move(iWin->Origin());
+		return clipRectRelativeToScreen;
+		}
+	else
+		{
+		return Rect();
+		}
+	}
+
+/** @see MWsStandardTextCursor */
+TUint RWsTextCursor::Flags() const
+	{
+	return iFlags&ETextCursorUserFlags;
+	}
+
+/** @see MWsStandardTextCursor */
+TRgb RWsTextCursor::Color() const
+	{
+	return iColor;
+	}
+
+/** @see MWsStandardTextCursor */
+TTimeIntervalMicroSeconds32 RWsTextCursor::FlashInterval() const
+	{
+	return iFlags&TTextCursor::EFlagNoFlash ? 0 : KFlashRate;
+	}
+
+TFlashState RWsTextCursor::CurrentCursorFlashState() const
+	{
+	if (IsFlashing())
+		{
+		return (CWsTop::CurrentFocusScreen()->Now().DateTime().MicroSecond()<KFlashRate)?EFlashOn:EFlashOff;
+		}
+	else
+		{
+		return EFlashOn;
+		}
+	}
+
+
+// Cursor sprite handling
+
+TBool TCursorSprite::iHidden=ETrue;
+RWsTextCursor *TCursorSprite::iCurrentCursor=NULL;
+
+//
+
+// Hide / Reveal text cursors.
+void TCursorSprite::Hide()
+	{
+	if (!iHidden && iCurrentCursor)
+		{
+		iHidden=ETrue;
+		if (iCurrentCursor->iCustomTextCursor)
+			{
+			iCurrentCursor->iCustomTextCursor->Deactivate();
+			}
+		else
+			{
+			iCurrentCursor->ScheduleReDrawNow();
+			}
+		}
+	}
+	
+void TCursorSprite::Reveal()
+	{
+	if(iHidden && iCurrentCursor)
+		{
+		iHidden=EFalse;
+		if (iCurrentCursor->iCustomTextCursor)
+			{
+			iCurrentCursor->iCustomTextCursor->Activate();
+			}
+		else
+			{
+			iCurrentCursor->ScheduleReDrawNow();
+			}
+		}
+	}
+
+void TCursorSprite::SetFocus(RWsTextCursor* aFocus,CWsClientWindow* aWin/*=NULL*/)
+	{
+	if (iCurrentCursor!=aFocus)
+		{
+		if (iCurrentCursor)
+			iCurrentCursor->ReleaseNode();
+		Hide();
+		SetCurrentCursor(aFocus, aWin);
+		}
+	}
+
+void TCursorSprite::SetCurrentCursor(RWsTextCursor* aFocus, CWsClientWindow* aWin)
+	{
+	if (aFocus && !aFocus->iCustomTextCursor)
+		aFocus->CreateNode();
+	iCurrentCursor = aFocus;
+	if (aWin && iCurrentCursor && iCurrentCursor->iCustomTextCursor)
+		{
+		iCurrentCursor->iCustomTextCursor->SetWindow(aWin);
+		}
+	Reveal();
+	}
+
+TBool TCursorSprite::IsStandardCursorActive()
+	{
+	return iCurrentCursor && !iCurrentCursor->iCustomTextCursor && !iHidden;
+	}
+