windowing/windowserver/nga/SERVER/wsdisplaychangeao.cpp
changeset 0 5d03bc08d59c
child 10 0e9202c0340c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nga/SERVER/wsdisplaychangeao.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,303 @@
+// Copyright (c) 2008-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:
+//
+
+/**
+ @file
+*/
+
+#include "wsdisplaychangeao.h"
+#include "ScrDev.H"
+#include "server.h"
+
+CWsDisplayChangeNotifier::CWsDisplayChangeNotifier(MWsDisplayControl* aNextLevelInterface, CScreen *aOwner)
+:CActive(EEventPriority), iNextLevelInterface(aNextLevelInterface), iOwner(aOwner)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CWsDisplayChangeNotifier* CWsDisplayChangeNotifier::NewL(MWsDisplayControl* aNextLevelInterface, CScreen *aOwner)
+	{
+	CWsDisplayChangeNotifier* self = new(ELeave) CWsDisplayChangeNotifier(aNextLevelInterface, aOwner);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CWsDisplayChangeNotifier::ConstructL()
+	{
+	iRetry = CEventQueueRetry::NewL();
+	}
+
+void CWsDisplayChangeNotifier::IssueNotificationRequest()
+	{
+	//before submitting request, save the last resolution list
+	iLastErr = iNextLevelInterface->GetResolutions(iLastResList);
+	if(iLastErr != KErrNone)
+		{
+		//probabally KErrDisconnect
+		iLastResList.Reset();
+		}
+	iNextLevelInterface->NotifyOnDisplayChange(iStatus);
+	SetActive();
+	}
+
+void CWsDisplayChangeNotifier::CancelNotificationRequest()
+	{
+	Cancel();
+	}
+
+void CWsDisplayChangeNotifier::RunL()
+	{
+	if(iStatus == KErrNone)
+		{
+		//IssueNotificationRequest() will overwrite iLastResList and iLastErr, save a copy first
+		TInt lastErr = iLastErr;
+		RArray<MWsDisplayControl::TResolution> lastResList;
+		CleanupClosePushL(lastResList);
+		lastResList.ReserveL(iLastResList.Count());
+		for(TInt i = 0; i < iLastResList.Count(); i++)
+			{
+			lastResList.Append(iLastResList[i]);
+			}
+		//submit request again, this should be called as early as possible in RunL(). Otherwise display change occurs
+		//before submitting the request will be missed.
+		IssueNotificationRequest();
+		
+		RArray<MWsDisplayControl::TResolution> currentResList;
+		CleanupClosePushL(currentResList);
+		TInt err = iNextLevelInterface->GetResolutions(currentResList);
+		if(err != KErrNone)
+			{
+			//probabally KErrDisconnect
+			currentResList.Reset();
+			}
+		//return code not equal also counts as an event
+		if(!IsResListEqual(currentResList, lastResList) || lastErr != err)
+			{
+			//first thing is to cancel the retry AO if it's running for the last event
+			iRetry->CancelRetry();
+			
+			iOwner->IncreaseDisplaySpinner();
+			//put display change event on queue
+			RPointerArray<CWsClient> clientArray;
+			CleanupClosePushL(clientArray);
+			User::LeaveIfError(iOwner->GetNotificationClients(clientArray));
+			TBool eventOnAllQueues = ETrue;
+			for(TInt i = 0; i < clientArray.Count(); i++)
+				{
+				if(!TWindowServerEvent::SendDisplayChangedEvents(clientArray[i], iOwner->ScreenNumber(),
+						iOwner->ConfigSpinner(), iOwner->DisplaySpinner()))
+					{
+					eventOnAllQueues = EFalse;
+					clientArray[i]->SetRetryFlag(EEventDisplayChanged);
+					}
+				}
+			CleanupStack::PopAndDestroy(&clientArray);
+			
+			//some event queues are full, kick off retry AO
+			if(!eventOnAllQueues)
+				{
+				iRetry->Init(iOwner);
+				iRetry->Retry(KRetryInitialDelay);
+				}
+						
+			//codes below are dealing with detach/attach
+			MWsDisplayPolicy* policy = iOwner->DisplayPolicy();
+			if((err == KErrDisconnected && lastErr != KErrDisconnected)
+					||(currentResList.Count() == 0 && lastResList.Count() != 0))
+				{
+				//The display is disconnected
+				if(policy)
+					{
+					TInt appMode = policy->SuitableAppMode(MWsDisplayPolicy::EDetach);
+					//Last app mode can be resumed when display is connected again from disconnection
+					iOwner->DisplayPolicy()->SetLastAppMode(iOwner->ScreenSizeMode());
+					//This gonna set the screen mode to smallest app mode
+					if(appMode >= 0)
+						{
+						iOwner->doSetScreenMode(appMode);
+						}
+					}
+				else
+					{
+					//if policy is not available, do a SetConfiguration set to the same config before disconnect
+					//this will update parameters for MDisplayMapping stored in CDisplayPolicy
+					TDisplayConfiguration config;
+					iNextLevelInterface->GetConfiguration(config);
+					iNextLevelInterface->SetConfiguration(config);
+					}
+				//stop DSA drawing as the above set screen mode is under disconnection and it won't
+				//go the normal routine to stop DSA drawing
+				iOwner->AbortAllDirectDrawing(RDirectScreenAccess::ETerminateScreenMode);
+				}
+			
+			if(currentResList.Count() > 0 && lastResList.Count() == 0)
+				{
+				//The display is connected
+				if(policy)
+					{
+					TInt appMode = policy->SuitableAppMode(MWsDisplayPolicy::EAttach);
+					//This gonna resume the screen mode to the one before disconnection
+					if(appMode >= 0)
+						{
+						iOwner->doSetScreenMode(appMode);
+						}
+					}
+				else
+					{
+					//if policy is not available, force a SetConfiguration to trigger a config change notification
+					//as the twips size in config is changed on attaching display though resolution may remain 0x0 
+					TDisplayConfiguration config;
+					config.SetResolution(currentResList[0].iPixelSize);
+					iOwner->SetConfiguration(config);
+					}
+				iOwner->RecalculateModeTwips();
+				}
+			}
+		CleanupStack::PopAndDestroy(2, &lastResList);
+		}
+	else if(iStatus != KErrCancel && iStatus != KErrNotSupported)
+		{
+		IssueNotificationRequest();	//This should be ok, not deadlock
+		}
+		
+	}
+
+TBool CWsDisplayChangeNotifier::IsResListEqual(RArray<MWsDisplayControl::TResolution>& aResListA, RArray<MWsDisplayControl::TResolution>& aResListB)
+	{
+	if (aResListA.Count() != aResListB.Count())
+		return EFalse;
+	
+	for(TInt i = 0; i < aResListA.Count(); i++)
+		{
+		if(aResListA[i].iPixelSize != aResListB[i].iPixelSize)
+			{
+			return EFalse;
+			}
+		if(aResListA[i].iTwipsSize != aResListB[i].iTwipsSize)
+			{
+			return EFalse;
+			}
+		if(!(aResListA[i].iFlags == aResListB[i].iFlags))
+			{
+			return EFalse;
+			}
+		}
+	
+	return ETrue;
+	}
+
+void CWsDisplayChangeNotifier::DoCancel()
+	{}
+
+CWsDisplayChangeNotifier::~CWsDisplayChangeNotifier()
+	{
+	Cancel();
+	iLastResList.Close();
+	delete iRetry;
+	}
+
+CWsConfigChangeNotifier::CWsConfigChangeNotifier(MWsDisplayControl* aNextLevelInterface, CScreen *aOwner)
+:CActive(EEventPriority), iNextLevelInterface(aNextLevelInterface), iOwner(aOwner)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CWsConfigChangeNotifier* CWsConfigChangeNotifier::NewL(MWsDisplayControl* aNextLevelInterface, CScreen *aOwner)
+	{
+	CWsConfigChangeNotifier* self = new(ELeave) CWsConfigChangeNotifier(aNextLevelInterface, aOwner);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+void CWsConfigChangeNotifier::ConstructL()
+	{
+	iRetry = CEventQueueRetry::NewL();
+	}
+
+void CWsConfigChangeNotifier::IssueNotificationRequest()
+	{
+	//Before submitting the request, save last configuration
+	iNextLevelInterface->GetConfiguration(iLastConfig);
+	iNextLevelInterface->NotifyOnConfigChange(iStatus);
+	SetActive();
+	}
+
+void CWsConfigChangeNotifier::CancelNotificationRequest()
+	{
+	Cancel();
+	}
+
+void CWsConfigChangeNotifier::RunL()
+	{
+	if(iStatus == KErrNone)
+		{
+		//IssueNotificationRequest() will overwrite iLastConfig, save a copy first
+		TDisplayConfiguration lastConfig(iLastConfig);
+		IssueNotificationRequest();
+		
+		TDisplayConfiguration currentConfig;
+		iNextLevelInterface->GetConfiguration(currentConfig);
+		if(!(currentConfig == lastConfig))
+			{
+			//first thing is to cancel the retry AO if it's running for the last event
+			iRetry->CancelRetry();
+			
+			iOwner->IncreaseConfigSpinner();
+			//put config change event on queue
+			RPointerArray<CWsClient> clientArray;
+			CleanupClosePushL(clientArray);
+			User::LeaveIfError(iOwner->GetNotificationClients(clientArray));
+			TBool eventOnAllQueues = ETrue;
+			for(TInt i = 0; i < clientArray.Count(); i++)
+				{
+				if(!TWindowServerEvent::SendDisplayChangedEvents(clientArray[i], iOwner->ScreenNumber(),
+						iOwner->ConfigSpinner(), iOwner->DisplaySpinner()))
+					{
+					eventOnAllQueues = EFalse;
+					clientArray[i]->SetRetryFlag(EEventDisplayChanged);					
+					}
+				}
+			
+			CleanupStack::PopAndDestroy(&clientArray);
+			//some event queues are full, kick off retry AO
+			if(!eventOnAllQueues)
+				{
+				iRetry->Init(iOwner);
+				iRetry->Retry(KRetryInitialDelay);
+				}
+			}
+		}
+	else if(iStatus != KErrCancel && iStatus != KErrNotSupported)
+		{
+		IssueNotificationRequest();
+		}
+	
+	}
+
+
+void CWsConfigChangeNotifier::DoCancel()
+	{}
+
+CWsConfigChangeNotifier::~CWsConfigChangeNotifier()
+	{
+	Cancel();
+	delete iRetry;
+	}
+
+