// EIKSHUT.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

//
// CEikShutter
//

#include <eikshut.h>
#include <eikenv.h>
#include <eikappui.h>
#include <basched.h>
#include <coemain.h>
#include <eikcmds.hrh>
#include <eikon.rsg>

class CKludgeScheduler : public CBaActiveScheduler
	{
public:
	inline TInt PublicLevel() const { return Level(); }
	};

const TInt KMaxNumEscKeysToSend=50;

enum
	{
	EMessagePending=0x01,
	ECleanupDestroyPending=0x02
	};

EXPORT_C CEikShutter::CEikShutter(TBool aMessagePending)
	: CActive(EActivePriorityWsEvents+1)
	{
	if (aMessagePending)
		iFlags=EMessagePending;
	iEikEnv=CEikonEnv::Static();
	CActiveScheduler::Add(this);
	iStartLevel=StartLevel();
	Queue();
	}

TInt CEikShutter::StartLevel() const
	{
	return ((CKludgeScheduler*)CActiveScheduler::Current())->PublicLevel();
	}

void CEikShutter::TerminateL()
	{
	const TBool cleanupDestroyPending=iFlags&ECleanupDestroyPending;
	if (cleanupDestroyPending)
		Cancel();
	if (iFlags&EMessagePending)
		{
		TUid uid;
		MessageLC(uid);
		CleanupStack::PopAndDestroy();
		}
	if (!cleanupDestroyPending)
		delete this;
	}

EXPORT_C CEikShutter::~CEikShutter()
	{
	Cancel();
	}

EXPORT_C void CEikShutter::DoCancel()
	{
	}

void CEikShutter::Queue()
	{
	TRequestStatus *pS=(&iStatus);
	User::RequestComplete(pS,0);
	SetActive();
	}

EXPORT_C void CEikShutter::RunL()
	{
	CleanupStack::PushL(this);
	if (iCount++>KMaxNumEscKeysToSend)
		{
		TerminateL(); // give up
		CleanupStack::Pop();
		return;
		}
	TInt startLevel=StartLevel();
	if (startLevel>iStartLevel)
		{
		TerminateL(); // give up: application has put up some query dialog
		CleanupStack::Pop();
		return;
		}
	iStartLevel=startLevel;
	CEikAppUi* appUi=iEikEnv->EikAppUi();
	if (appUi->IsDisplayingMenuOrDialog())
		{
		Queue(); // before any call to CActiveScheduler::Start() from below
		TKeyEvent key;
		key.iCode=EKeyEscape;
		key.iModifiers=0;
		iEikEnv->SimulateKeyEventL(key,EEventKey);
		}
	else if (appUi->ContainerAppUi() || !(iFlags&EMessagePending))
		{
		Queue(); // before any call to CActiveScheduler::Start() from below
		iFlags|=ECleanupDestroyPending;
		appUi->HandleCommandL(EEikCmdExit); // will leave when really exits
		iFlags&=(~ECleanupDestroyPending);
		}
	else
		{ // don't call Queue() in this case, else crash if switch files throws up dialog with wait
		ProcessMessageL(appUi);
		CleanupStack::PopAndDestroy();
		return;
		}
	CleanupStack::Pop();
	}

TPtr8 CEikShutter::MessageLC(TUid& aUid)
	{
	TPtr8 msgPtr(NULL,0);
	User::LeaveIfError(iEikEnv->RootWin().FetchMessage(aUid,msgPtr));
	CleanupStack::PushL((TAny*)msgPtr.Ptr());
	return msgPtr;
	}

EXPORT_C void CEikShutter::ProcessMessageL(CEikAppUi* aAppUi)
	{
	TUid uid;
	TPtr8 msgPtr=MessageLC(uid);
	aAppUi->ProcessMessageL(uid,msgPtr);
	CleanupStack::PopAndDestroy(); // msgPtr
	}
