windowing/windowserver/nonnga/SERVER/REDRAWQ.CPP
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/REDRAWQ.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,261 @@
+// Copyright (c) 1996-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:
+//
+
+// Window server redraw queue handling
+//
+#include <e32std.h>
+#include "server.h"
+#include "rootwin.h"
+#include "windowgroup.h"
+#include "walkwindowtree.h"
+#include "EVQUEUE.H"
+#include "panics.h"
+#include "wstop.h"
+#include "wstraces.h"
+
+const TInt KGranularity = 10;
+
+void TWsRedrawEvent::SetHandle(TUint aHandle)
+	{
+	iHandle=aHandle;
+	}
+
+void TWsRedrawEvent::SetRect(TRect aRect)
+	{
+	iRect=aRect;
+	}
+
+TWsRedrawEvent CRedrawQueue::iNullRedrawEvent;
+
+CRedrawQueue::CRedrawQueue(CWsClient *aOwner) : CEventBase(aOwner)
+	{
+	__DECLARE_NAME(_S("CRedrawQueue"));
+	}
+
+void CRedrawQueue::ConstructL()
+	{
+	iRedrawTrigger=EFalse;
+	iRedraws=new(ELeave) CArrayFixSeg<TRedraw>(KGranularity);
+	iKeyPriority=new(ELeave) TKeyArrayFix(_FOFF(TRedraw,iPriority),ECmpTUint32);
+	iKeyWindow=new(ELeave) TKeyArrayFix(_FOFF(TRedraw,iRedraw),ECmpTUint32);
+	Mem::FillZ(&iNullRedrawEvent,sizeof(iNullRedrawEvent));
+	}
+
+CRedrawQueue::~CRedrawQueue()
+	{
+	delete iRedraws;
+	delete iKeyPriority;
+	delete iKeyWindow;
+	}
+
+void CRedrawQueue::ReCalcOrder()
+	{
+	const TInt redrawsCount=iRedraws->Count();
+	for(TInt index=0;index<redrawsCount;index++)
+		{
+		TRedraw *redraw=&iRedraws->At(index);
+		redraw->iPriority=static_cast<CWsClientWindow*>(redraw->iRedraw->WsWin())->RedrawPriority();
+		}
+	iRedraws->Sort(*iKeyPriority);
+	}
+
+void CRedrawQueue::AddInvalid(CWsWindowRedraw *aRedrawWin) 
+//
+// Add a window to the update list.
+//
+	{
+	TInt index;
+	TRedraw redraw;
+
+	redraw.iRedraw=aRedrawWin;
+	if (iRedraws->Find(redraw,*iKeyWindow,index)!=0)
+		{
+		redraw.iPriority=static_cast<CWsClientWindow*>(aRedrawWin->WsWin())->RedrawPriority();
+		TRAPD(err,iRedraws->InsertIsqAllowDuplicatesL(redraw,*iKeyPriority));
+		if (err!=KErrNone)
+			{
+			WS_ASSERT_DEBUG(err==KErrNoMemory,EWsPanicRedrawQueueError);
+			iAllocError=ETrue;
+			}
+		iRedrawTrigger=ETrue;
+		}
+	}
+
+void CRedrawQueue::DeleteFromQueue(TInt aIndex)
+	{
+	iRedraws->Delete(aIndex,1);
+	
+	//We are certain we will need iRedraws again, so it would be silly to compress away the last KGranularity slots.
+	const TInt count = iRedraws->Count();
+	if((count >= KGranularity) && (count % KGranularity == 0))
+		{
+		iRedraws->Compress();
+		}
+	}
+
+void CRedrawQueue::RemoveInvalid(CWsWindowRedraw *aRedrawWin)
+//
+// remove the window from the invalid window list.
+// harmless to call if the window is not in the list.
+//
+	{
+	TInt index;
+	TRedraw redraw;
+
+	redraw.iRedraw=aRedrawWin;
+	redraw.iPriority=0;
+	if ((iRedraws->Find(redraw,*iKeyWindow,index))==KErrNone)
+		DeleteFromQueue(index);
+	}
+
+TBool CRedrawQueue::TriggerRedraw()
+//
+// Trigger any pending redraw messages in the queue
+// Returns ETrue if a redraw was sent, EFalse if not.
+//
+	{
+	WS_TRACE_SERVER_TRIGGERREDRAW();	
+	TBool ret=EFalse;
+	if (iRedrawTrigger)
+		{
+		iRedrawTrigger=EFalse;
+		if (!iEventMsg.IsNull() && (iRedraws->Count()>0 || iAllocError))
+			{
+			SignalEvent();
+			ret=ETrue;
+			}
+		}
+	return(ret);
+	}
+
+void CRedrawQueue::EventReady(const RMessagePtr2& aEventMsg)
+//
+// Queue a read of an event from the queue
+//
+	{
+	CEventBase::EventReady(aEventMsg);
+	iRedrawTrigger=ETrue;
+	TriggerRedraw();
+	}
+
+TBool CRedrawQueue::FindOutstandingRedrawEvent(CWsWindowRedraw& aRedraw, TWsRedrawEvent& aEvent)
+	{
+	TRect rect;
+	if (aRedraw.GetRedrawRect(rect))
+		{
+		aEvent.SetRect(rect);
+		aEvent.SetHandle(aRedraw.WsWin()->ClientHandle());
+		CEventBase::GetData(&aEvent,sizeof(aEvent));
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+TBool CRedrawQueue::FindWindowNeedingRedrawEvent(TWsRedrawEvent& aEvent)
+	{
+#if defined(_DEBUG)
+	CWsWindowRedraw* previousRedraw = NULL;
+#endif
+	// search all screens
+	TInt invalidWindows = 0;
+	for (TInt screenNo = 0; screenNo < CWsTop::NumberOfScreens(); ++screenNo)
+		{
+		CWsRootWindow* rootWindow = CWsTop::Screen(screenNo)->RootWindow();
+		for (CWsWindowGroup *groupWin = rootWindow->Child(); groupWin; groupWin = groupWin->NextSibling())
+			{
+			if (groupWin->WsOwner() == iWsOwner)
+				{
+				CWsWindowRedraw* redrawWin = NULL;
+				// use a window tree walk that can be resumed to find windows with an invalid region
+				TResumableWalkWindowTreeFindInvalid wwt(&redrawWin);
+				groupWin->WalkWindowTree(wwt, EWalkChildren, EFalse);
+				while (redrawWin != NULL)
+					{
+					WS_ASSERT_DEBUG(redrawWin != previousRedraw, EWsPanicRedrawQueueError);
+					// (the window may not actually need the client to redraw it, e.g. a CWsBlankWindow can redraw itself)
+					if (FindOutstandingRedrawEvent(*redrawWin, aEvent))
+						{
+						return ETrue;
+						}
+					else
+						{ // continue the Tree Walk
+#if defined(_DEBUG)
+						previousRedraw = redrawWin;
+#endif
+						if (redrawWin->NeedsRedraw())
+							{ // needs to be redrawn later?
+							++invalidWindows;
+							}
+						redrawWin = NULL;
+						groupWin->WalkWindowTree(wwt, EWalkChildren, ETrue);
+						}
+					}
+				}
+			}
+		}
+
+	if (invalidWindows == 0)
+		{ // error recovery is complete
+		iAllocError = 0;
+		}
+	return EFalse;
+	}
+
+void CRedrawQueue::GetData()
+//
+// If there is an outstanding redraw event in the queue, reply with it's data
+//
+	{
+	CWsWindowRedraw *redraw;
+	TWsRedrawEvent event;
+
+	while (iRedraws->Count()>0)
+		{
+		redraw=(*iRedraws)[0].iRedraw;
+		if (FindOutstandingRedrawEvent(*redraw,event))
+			{
+			return;
+			}
+		TInt toDelete=0;
+		if (redraw!=(*iRedraws)[0].iRedraw)
+			{		//In low memory conditions calls to FindOutstandingRedrawEvent can cause extra entries to be added to the array
+			TRedraw redrawFind;
+			redrawFind.iRedraw=redraw;
+			iRedraws->Find(redrawFind,*iKeyWindow,toDelete);
+			}
+		DeleteFromQueue(toDelete);
+		}
+
+	if (iAllocError && FindWindowNeedingRedrawEvent(event))
+		{
+		return;
+		}
+
+	CEventBase::GetData(&iNullRedrawEvent,sizeof(iNullRedrawEvent));
+	}
+
+TUint CRedrawQueue::RedrawPriority(CWsWindowRedraw *aRedrawWin)
+	{
+	TInt index;
+	TRedraw redraw;
+	TUint priority=0;
+	redraw.iRedraw=aRedrawWin;
+
+	if ((iRedraws->Find(redraw,*iKeyWindow,index))==KErrNone)
+		{
+		priority=iRedraws->At(index).iPriority;
+		}
+	return priority;
+	}