windowing/windowserver/nga/SERVER/wsdisplaychangeao.cpp
author Faisal Memon <faisal.memon@nokia.com>
Thu, 06 May 2010 11:31:11 +0100
branchNewGraphicsArchitecture
changeset 47 48b924ae7197
parent 0 5d03bc08d59c
child 97 0e9202c0340c
child 110 7f25ef56562d
child 116 171fae344dd4
permissions -rw-r--r--
Applied patch 1, to provide a syborg specific minigui oby file. Need to compare this with the "stripped" version currently in the tree. This supplied version applies for Nokia builds, but need to repeat the test for SF builds to see if pruning is needed, or if the file needs to be device-specific.

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