windowing/windowserver/nga/SERVER/wsdisplaychangeao.cpp
author Faisal Memon <faisal.memon@nokia.com>
Fri, 25 Jun 2010 17:49:58 +0100
branchEGL_MERGE
changeset 105 158b2308cc08
parent 0 5d03bc08d59c
child 97 0e9202c0340c
child 110 7f25ef56562d
child 116 171fae344dd4
permissions -rw-r--r--
Fix def files so that the implementation agnostic interface definition has no non-standards defined entry points, and change the eglrefimpl specific implementation to place its private entry points high up in the ordinal order space in the implementation region, not the standards based entrypoints region.

// 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;
	}