// COEMAIN.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <f32file.h>
#include <s32stor.h>
#include <s32file.h>
#include <brdcst.h>
#include <coemain.h>
#include <coepriv.h>
#include "coetls.h"
#include <coepanic.h>
#include <coever.h>
#include <coecntrl.h>
#include <coeauib.h>
#include <coeerror.h>
#include <barsread.h>
#include <bautils.h>

_LIT(KLitFrontEndProcessorDirectoryName, "\\system\\fep\\");

#ifdef _UNICODE
#define KUidFepDll KUidFepDll16
#define KFepNameStreamUid KFepNameStreamUid16
#else
#define KUidFepDll KUidFepDll8
#define KFepNameStreamUid KFepNameStreamUid8
#endif

const TInt KFepNameStreamUid16=0x10003A42;
const TInt KFepNameStreamUid8=0x10001482;
const TUid KUidFepDll8={0x10001189};
const TUid KUidFepDll16={0x10003A43};

//
// Class CCoeEnvExtra
//

class CCoeEnvExtra : public CBase
	{
public:
	struct SFep
		{
		CCoeFep* iFep;
		RLibrary iFepLibrary;
		};
public:
	static void DestroyFep(TAny* aFep);
	static void DestroyFep(SFep& aFep);
public:
	CCoeRedrawer* iRedrawer;
	CCoeFepParameters* iFepParameters;
	HBufC* iFileNameOfDefaultFepDll;
	TUid iUidOfDefaultFep;
	CBrdBroadcastServerSession* iBroadcastServerSession;
	CCoeFepTracker* iFepTracker;
	CCoeFepLoader* iFepLoader;
	SFep iFep[2];
	TInt iFepIndex;
	MCoeFepAwareItem* iFocusedFepAwareItem; // this pointer does not own anything
	TCoeFepAwareItemIsFocusedFunction iFepAwareItemIsFocusedFunction;
	TInt iNumberOfNestedSetFocusCalls;
	CArrayFix<MCoeObserverOfFocusedFepAwareItem*>* iArrayOfObserversOfFocusedFepAwareItem;
	CArrayFix<MCoeObserverOfLoadedFep*>* iArrayOfObserversOfLoadedFep;
	CArrayFix<MCoeFocusObserver*>* iArrayOfFocusObservers;
	CArrayFix<MCoeForegroundObserver*>* iArrayOfForegroundObservers;
	CArrayFix<MCoeFepObserver*>* iArrayOfFepObservers;
	CArrayFix<TInt>* iResFileAccessCount;
	};

void CCoeEnvExtra::DestroyFep(TAny* aFep)
	{
	DestroyFep(*(CCoeEnvExtra::SFep*)aFep);
	}

void CCoeEnvExtra::DestroyFep(SFep& aFep)
	{
	delete (CBase*)aFep.iFep;
	aFep.iFep=NULL;
	aFep.iFepLibrary.Close();
	}

GLDEF_C void Panic(TCoePanic aPanic)
	{
	User::Panic(_L("CONE"),aPanic);
	}

GLDEF_C TInt E32Dll(TDllReason /*aReason*/)
	{
	return(KErrNone);
	}

//
// Class CCoeScheduler
//

CCoeScheduler::CCoeScheduler(CCoeEnv* aCoeEnv)
	{
	iCoeEnv=aCoeEnv;
	iFlush=ETrue; // Set the default flushing behaviour to flush automatically
	}

void CCoeScheduler::WaitForAnyRequest()
	{
	iCoeEnv->ReadEvent();
	User::WaitForAnyRequest();
	}

void CCoeScheduler::DisplayError(TInt aError) const
	{
	iCoeEnv->HandleError(aError);
	}

//
// class CCoeRedrawer
//

CCoeRedrawer::CCoeRedrawer(RWsSession* aWsSession)
	: CActive(EActivePriorityRedrawEvents)
	{
	iWsSession=aWsSession;
	CActiveScheduler::Add(this);
	}

CCoeRedrawer::~CCoeRedrawer()
	{
	Cancel();
	}

void CCoeRedrawer::RunL()
	{
	TWsRedrawEvent redraw;
	iWsSession->GetRedraw(redraw);
	CCoeControl* window=(CCoeControl*)redraw.Handle();
#if defined(_DEBUG)
	if (window)
		{
		TRAPD(err, window->HandleRedrawEvent(redraw.Rect()));
		__ASSERT_ALWAYS(err==KErrNone,Panic(ECoePanicLeaveWithoutTrapDuringRedraw));
		}
#else
	if (window)
		window->HandleRedrawEvent(redraw.Rect());
#endif
	}

void CCoeRedrawer::Queue()
	{
	if (IsActive())
		return;
	iWsSession->RedrawReady(&iStatus);
	SetActive();
	}

void CCoeRedrawer::DoCancel()
	{
	iWsSession->RedrawReadyCancel();
	}

//
// Class CCoeEnv
//

const TInt KErrorContextTextLength=80;
const TInt KErrorTextLength=80;

EXPORT_C CCoeEnv::CCoeEnv() : CActive(EActivePriorityWsEvents)
	{
	__DECLARE_NAME(_S("CCoeEnv"));
	__ASSERT_ALWAYS(!TheCoe(),Panic(ECoePanicEnvironmentAlreadyExists));
	SetTheCoe(this);
	__UHEAP_MARK;
	iCleanup=CTrapCleanup::New();
	if (!iCleanup)
		Panic(ECoePanicStartupHeapTooSmall);
	}

EXPORT_C void CCoeEnv::ExecuteD()
	{
	TRAPD(exitCondition,CActiveScheduler::Start());
	if (exitCondition!=KLeaveExit)
		Panic(ECoePanicLeaveWithoutTrap);
	PrepareToExit();
	DestroyEnvironment();
	}

EXPORT_C void CCoeEnv::PrepareToExit()
	{
	if (iAppUi)
		iAppUi->PrepareToExit();
	}

EXPORT_C void CCoeEnv::RunL()
	{
	switch (iStatus.Int())
		{
	case KErrNone:
		break;
	case KErrCancel:
	case KErrServerTerminated:
		return;
	default:
		Panic(ECoePanicWservBlindCommandFailed);
		}
	TWsEvent event;
	iWsSession.GetEvent(event);
	CCoeControl* window=(CCoeControl*)event.Handle();
	if (!window)
		return;
	iLastEvent=event;
	iAppUi->HandleWsEventL(event,window);
	}

EXPORT_C void CCoeEnv::SimulateKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{
	TWsEvent event;
	*event.Key()=aKeyEvent;
	event.SetType(aType);
	event.SetTimeNow();
	iLastEvent=event;
	iAppUi->HandleWsEventL(event,NULL);
	}

EXPORT_C void CCoeEnv::DoCancel()
	{
	iWsSession.EventReadyCancel();
	}

EXPORT_C void CCoeEnv::SuppressNextFlush()
	{
	((CCoeScheduler*)CActiveScheduler::Current())->SetFlush(EFalse);
	}

void CCoeEnv::ReadEvent()
	{
	iExtra->iRedrawer->Queue();
	if (IsActive())
		{
		CCoeScheduler* coeScheduler = (CCoeScheduler*)CActiveScheduler::Current();
		if (coeScheduler->Flush())
			iWsSession.Flush();
		else
			coeScheduler->SetFlush(ETrue);
		}
	else
		{
   		iWsSession.EventReady(&iStatus);
		SetActive();
		}
	}

EXPORT_C void CCoeEnv::HandleError(TInt /*aErrorValue*/)
	{
	}

EXPORT_C void CCoeEnv::BringOwnerToFront()
	{
	if (iRootWin.WsHandle()) // else initialization hasn't got that far yet
		iRootWin.SetOrdinalPosition(KOrdinalPositionSwitchToOwningWindow);
	}

EXPORT_C void CCoeEnv::DestroyEnvironment()
	{
	BringOwnerToFront();
	if (iExtra!=NULL)
		CCoeEnvExtra::DestroyFep(iExtra->iFep[iExtra->iFepIndex]);
	delete(iAppUi); // must be destroyed before the iExtra observers
	if (iExtra!=NULL)
		{
		delete iExtra->iRedrawer;
		delete (CBase*)iExtra->iFepParameters;
		delete iExtra->iFileNameOfDefaultFepDll;
		delete iExtra->iFepTracker;
		delete iExtra->iBroadcastServerSession; // can only be deleted when iExtra->iFepTracker has been deleted
		delete iExtra->iFepLoader;
		delete iExtra->iArrayOfObserversOfFocusedFepAwareItem;
		delete iExtra->iArrayOfObserversOfLoadedFep;
		delete iExtra->iArrayOfFocusObservers;
		delete iExtra->iArrayOfForegroundObservers;
		delete iExtra->iArrayOfFepObservers;
		}
	delete(iSystemGc);
	ReleaseScreenFont(CONST_CAST(CFont*,iNormalFont));
	iRootWin.Close();
	DestroyScreen();
	__ASSERT_DEBUG(!iWsSession.ResourceCount(),Panic(ECoePanicWservResourceNotFreed));
	Cancel();
	iWsSession.Close();
	DestroyAllResourceFiles();
	if (iExtra)
		{
//		__ASSERT_DEBUG(iExtra->iResFileAccessCount->Count()==0,Panic(ECoePanicResourceFileNotDeleted));
		delete iExtra->iResFileAccessCount;
		delete iExtra; // can only be done when iAppUi has been destroyed as destroying iAppUi may destroy some controls owned by the control stack, and these controls may call SetFocus when they are destroyed, SetFocus internally referencing iExtra->iNumberOfNestedSetFocusCalls
		}
	__ASSERT_DEBUG(!iFsSession.ResourceCount(),Panic(ECoePanicF32ResourceNotFreed));
	iFsSession.Close();
	delete this;
	}

EXPORT_C CCoeEnv::~CCoeEnv()
	{
	delete CActiveScheduler::Current();
	delete iErrorText;
	delete iErrorContextText;
	delete iCleanup;
	__UHEAP_MARKEND;
	}

EXPORT_C void CCoeEnv::DestroyScreen()
	{ // subclassers can do more
	delete iScreen;
	}

EXPORT_C CCoeAppUiBase* CCoeEnv::SetAppUi(CCoeAppUiBase* aAppUi)
	{
	CCoeAppUiBase* previous=iAppUi;
	iAppUi=aAppUi;
	return(previous);
	}

EXPORT_C void CCoeEnv::ConstructL()
	{
	iExtra=new(ELeave) CCoeEnvExtra;
	iErrorText=new(ELeave) TBuf<KErrorTextLength>;
	iErrorContextText=new(ELeave) TBuf<KErrorContextTextLength>;
	CreateActiveSchedulerL();
	CActiveScheduler::Add(this);
	ConnectToFileServerL();
	ConnectToWindowServerL();
	InitScreenL();
	InitRootWindowL();
	InitSystemFontsL();
	InitSystemGcL();
	iExtra->iRedrawer=new(ELeave) CCoeRedrawer(&iWsSession);
	// iExtra->iFepParameters is set in SetUpFepL
	// iExtra->iFileNameOfDefaultFepDll is created in SetUpFepL
	iExtra->iBroadcastServerSession=CBrdBroadcastServerSession::NewL(2); // 2=1+1 (1 asynchronous request, 1 synchronous request)
	iExtra->iFepTracker=CCoeFepTracker::NewL(*iExtra->iBroadcastServerSession, *this);
	iExtra->iFepLoader=CCoeFepLoader::NewL(*this, iExtra->iFepLoader);
	iExtra->iArrayOfObserversOfFocusedFepAwareItem=new(ELeave) CArrayFixFlat<MCoeObserverOfFocusedFepAwareItem*>(2);
	iExtra->iArrayOfObserversOfLoadedFep=new(ELeave) CArrayFixFlat<MCoeObserverOfLoadedFep*>(2);
	iExtra->iArrayOfFocusObservers=new(ELeave) CArrayFixFlat<MCoeFocusObserver*>(2);
	iExtra->iArrayOfForegroundObservers=new(ELeave) CArrayFixFlat<MCoeForegroundObserver*>(2);
	iExtra->iArrayOfFepObservers=new(ELeave) CArrayFixFlat<MCoeFepObserver*>(2);
	}

void CCoeEnv::CreateActiveSchedulerL()
	{
	CActiveScheduler::Install(new(ELeave) CCoeScheduler(this));
	}

void CCoeEnv::ConnectToFileServerL()
	{
	User::LeaveIfError(iFsSession.Connect());
	}

void CCoeEnv::ConnectToWindowServerL()
	{
	User::LeaveIfError(iWsSession.Connect());
	}

void CCoeEnv::InitScreenL()
	{
	iScreen=new(ELeave) CWsScreenDevice(iWsSession);
	User::LeaveIfError(iScreen->Construct());
	}

void CCoeEnv::InitRootWindowL()
	{
	iRootWin=RWindowGroup(iWsSession);
	User::LeaveIfError(iRootWin.Construct((TUint32)this));
	}

EXPORT_C void CCoeEnv::InitSystemFontsL()
	{ 
#pragma message(__FILE__ " : Hard coded name of font - may need to change for some locales")
	TFontSpec spec(_L("Arial"),200); // 10 points
	iNormalFont=CreateScreenFontL(spec);
	}

void CCoeEnv::InitSystemGcL()
	{
	iSystemGc=CreateGcL();
	}

EXPORT_C CWindowGc* CCoeEnv::CreateGcL()
	{
	CGraphicsContext* temp;
	User::LeaveIfError(iScreen->CreateContext(temp));
	return((CWindowGc*)temp);
	}

EXPORT_C CFbsFont* CCoeEnv::CreateDeviceFontL(CGraphicsDevice* aDevice,const TFontSpec& aFontSpec)
	{
	CFont* ret;
	User::LeaveIfError(aDevice->GetNearestFontInTwips(ret,aFontSpec));
	return((CFbsFont*)ret);
	}

EXPORT_C CFbsFont* CCoeEnv::CreateScreenFontL(const TFontSpec& aFontSpec)
	{
	return(CreateDeviceFontL(iScreen,aFontSpec));
	}

EXPORT_C void CCoeEnv::ReleaseScreenFont(CFont* aFont) const
	{
	if (aFont)
		iScreen->ReleaseFont(aFont);
	}

EXPORT_C void CCoeEnv::Flush(TTimeIntervalMicroSeconds32 aDelay)
	{
	iWsSession.Flush();
	User::After(aDelay);
	}

EXPORT_C TBool CCoeEnv::IsWservEventPending() const
	{
	return(iStatus.Int()!=KRequestPending);
	}

EXPORT_C TBool CCoeEnv::IsRedrawEventPending() const
	{
	return(iExtra->iRedrawer->iStatus.Int()!=KRequestPending);
	}

EXPORT_C void CCoeEnv::ReadResourceAsDes8(TDes8& aDes,TInt aResourceId) const
	{
	RResourceFile& rf=ResourceFileForId(aResourceId);
	FOREVER
		{
		TRAPD(err,rf.ReadL(aDes,aResourceId));
		if (err==KErrNone)
			return;
		CBaActiveScheduler::DisplayExtendedError(KUidConeDll,KErrCoeFailedToReadFromProgDisk);
		}
	}

EXPORT_C void CCoeEnv::ReadResourceAsDes16(TDes16& aDes,TInt aResourceId) const
	{
 // Reading Unicode string
	RResourceFile& rf=ResourceFileForId(aResourceId);
	FOREVER
		{
		TPtr8 readBuffer((TText8* ) aDes.Ptr(),aDes.MaxSize());
		TRAPD(err,rf.ReadL(readBuffer,aResourceId));
 		__ASSERT_DEBUG((readBuffer.Length()%2)==0||(err==KErrNone),Panic(ECoePanicWrongResourceFormat));
		aDes.SetLength((readBuffer.Length()+1)>>1);
		if (err==KErrNone)
			return;
		CBaActiveScheduler::DisplayExtendedError(KUidConeDll,KErrCoeFailedToReadFromProgDisk);
		}
	}

EXPORT_C HBufC8* CCoeEnv::AllocReadResourceAsDes8L(TInt aResourceId) const
	{
	RResourceFile& rf=ResourceFileForId(aResourceId);
	return(rf.AllocReadL(aResourceId));
	}

EXPORT_C HBufC16* CCoeEnv::AllocReadResourceAsDes16L(TInt aResourceId) const
	{
 // Reading Unicode string
	RResourceFile& rf=ResourceFileForId(aResourceId);
	HBufC8* readBuffer=rf.AllocReadLC(aResourceId);
 	__ASSERT_DEBUG((readBuffer->Length()%2)==0,Panic(ECoePanicWrongResourceFormat));
	const TPtrC16 ptrReadBuffer((TText16*) readBuffer->Ptr(),(readBuffer->Length()+1)>>1);
	HBufC16* textBuffer=HBufC16::NewL(ptrReadBuffer.Length());
	*textBuffer=ptrReadBuffer;
	CleanupStack::PopAndDestroy();
	return textBuffer;
	}

EXPORT_C HBufC8* CCoeEnv::AllocReadResourceAsDes8LC(TInt aResourceId) const
	{
	RResourceFile& rf=ResourceFileForId(aResourceId);
	return(rf.AllocReadLC(aResourceId));
	}

EXPORT_C HBufC16* CCoeEnv::AllocReadResourceAsDes16LC(TInt aResourceId) const
	{
 // Reading Unicode string
	HBufC16* textBuffer=AllocReadResourceAsDes16L(aResourceId);
	CleanupStack::PushL(textBuffer);
	return textBuffer;
	}

EXPORT_C void CCoeEnv::CreateResourceReaderLC(TResourceReader& aReader,TInt aResourceId) const
	{
	RResourceFile& rf=ResourceFileForId(aResourceId);
	HBufC8* resource=rf.AllocReadLC(aResourceId);
	aReader.SetBuffer(resource);
	}

struct STempCleanup
	{
	CArrayFix<TInt>* iArray;
	};
LOCAL_C void DeleteTemp(TAny* aPtr)
	{
	STempCleanup& temp=*(STempCleanup*)aPtr;
	temp.iArray->Delete(temp.iArray->Count()-1);
	}

EXPORT_C TInt CCoeEnv::AddResourceFileL(const TDesC& aFileName)
	{
	if (!iResourceFileArray)
		iResourceFileArray=new(ELeave) CArrayFixFlat<RResourceFile>(2); // granularity of 2
	if (!iExtra->iResFileAccessCount)
		iExtra->iResFileAccessCount=new(ELeave) CArrayFixFlat<TInt>(2);
	RResourceFile resourceFile;
	resourceFile.OpenL(iFsSession,aFileName);
	CleanupClosePushL(resourceFile);
	resourceFile.ConfirmSignatureL(ResourceFileVersionNumber());
	TInt offset=resourceFile.Offset();
	if (!offset)
		Panic(ECoePanicResourceFileHasNullName);
	TInt count=iResourceFileArray->Count();
	while (count--)
		{
		TInt previousOffset=(*iResourceFileArray)[count].Offset();
		if (offset==previousOffset)
			break;
	//		CBaActiveScheduler::LeaveForAlert(KUidConeDll,KErrCoeResourceFileDuplicateOffset);
		}
	if (count>=0)
		{
		TInt accessCount=(*(iExtra->iResFileAccessCount))[count]+1;
		(*(iExtra->iResFileAccessCount))[count]=accessCount;
		}
	else
		{
		TInt accessCount=1;
		iExtra->iResFileAccessCount->AppendL(accessCount);
		STempCleanup resCleanup;
		resCleanup.iArray=iExtra->iResFileAccessCount;
		CleanupStack::PushL(TCleanupItem(DeleteTemp,&resCleanup));
		iResourceFileArray->AppendL(resourceFile);
		CleanupStack::Pop(); // resCleanup
		}
	CleanupStack::Pop(); // resourceFile
	return(offset);
	}

EXPORT_C void CCoeEnv::DeleteResourceFile(TInt aOffset)
	{
	if (!aOffset)
		return;
	TInt count=iResourceFileArray->Count();
	while (count--)
		{
		RResourceFile& data=(*iResourceFileArray)[count];
		if (data.Offset()==aOffset)
			{
			TInt accessCount=(*(iExtra->iResFileAccessCount))[count];
			if (--accessCount==0)
				{
				data.Close();
				iResourceFileArray->Delete(count);
				iExtra->iResFileAccessCount->Delete(count);
				}
			else
				(*(iExtra->iResFileAccessCount))[count]=accessCount;
			return;
			}
		}
	Panic(ECoePanicUnknownResourceFile);
	}

RResourceFile& CCoeEnv::ResourceFileForId(TInt aResourceId) const
	{
	TInt count=iResourceFileArray->Count();
	FOREVER
		{
		if (!count--)
			Panic(ECoePanicNoResourceFileForId);
		RResourceFile& resourceFile=(*iResourceFileArray)[count];
		if (resourceFile.OwnsResourceId(aResourceId))
			return resourceFile;
		}
	}

void CCoeEnv::DestroyAllResourceFiles()
	{
	if (!iResourceFileArray)
		return;
	TInt count=iResourceFileArray->Count();
	while (count--)
		{
		RResourceFile& resourceFile=(*iResourceFileArray)[count];
		resourceFile.Close();
		}
	delete(iResourceFileArray);
	}

EXPORT_C CDesC8ArrayFlat* CCoeEnv::ReadDesC8ArrayResourceL(TInt aResourceId)
	{
	TResourceReader reader;
	CreateResourceReaderLC(reader,aResourceId);
	CDesC8ArrayFlat* array=reader.ReadDesC8ArrayL();
	CleanupStack::PopAndDestroy();
	return(array);
	}

EXPORT_C CDesC16ArrayFlat* CCoeEnv::ReadDesC16ArrayResourceL(TInt aResourceId)
	{
	// Reading array of Unicode descriptors
	TResourceReader reader;
	CreateResourceReaderLC(reader,aResourceId);
	CDesC16ArrayFlat* array=reader.ReadDesC16ArrayL();
	CleanupStack::PopAndDestroy();
	return(array);
	}

EXPORT_C void CCoeEnv::Format128(TDes& aDes,TInt aResourceId,...)
	{
	TBuf<128> formatString;
	ReadResource(formatString,aResourceId);
	VA_LIST list;
	VA_START(list,aResourceId);
	aDes.FormatList(formatString,list);
	}

EXPORT_C void CCoeEnv::Format256(TDes& aDes,TInt aResourceId,...)
	{
	TBuf<256> formatString;
	ReadResource(formatString,aResourceId);
	VA_LIST list;
	VA_START(list,aResourceId);
	aDes.FormatList(formatString,list);
	}

EXPORT_C TInt CCoeEnv::ResourceFileVersionNumber() const
	{ // will generally be replaced
	return(0);
	}

EXPORT_C void CCoeEnv::LeaveWithErrorText(const TDesC& aMsg,const TDesC* aContextText)
	{
	BaflUtils::CopyWithTruncation(ErrorText(),aMsg);
	TDes& errContextText=ErrorContextText();
	errContextText.Zero();
	if (aContextText)
		BaflUtils::CopyWithTruncation(errContextText,*aContextText);
	User::Leave(KErrExtendedWithText);
	}

EXPORT_C TVersion CCoeEnv::Version()
	{ // static
	return(TVersion(KCoeMajorVersionNumber,KCoeMinorVersionNumber,KCoeBuildVersionNumber));
	}

EXPORT_C CCoeEnv* CCoeEnv::Static()
	{ // static
	return(TheCoe());
	}

EXPORT_C void CCoeEnv::AddObserverOfFocusedFepAwareItemL(MCoeObserverOfFocusedFepAwareItem& aObserverOfFocusedFepAwareItem)
	{
	__ASSERT_ALWAYS(&aObserverOfFocusedFepAwareItem!=NULL, Panic(ECoePanicIllegalNullParameter1));
	CArrayFix<MCoeObserverOfFocusedFepAwareItem*>* const arrayOfObserversOfFocusedFepAwareItem=iExtra->iArrayOfObserversOfFocusedFepAwareItem;
	for (TInt i=arrayOfObserversOfFocusedFepAwareItem->Count()-1; i>=0; --i)
		{
		__ASSERT_ALWAYS((*arrayOfObserversOfFocusedFepAwareItem)[i]!=&aObserverOfFocusedFepAwareItem, Panic(ECoePanicFocusObserverHasAlreadyBeenAdded));
		}
	arrayOfObserversOfFocusedFepAwareItem->AppendL(&aObserverOfFocusedFepAwareItem);
	}

EXPORT_C void CCoeEnv::RemoveObserverOfFocusedFepAwareItem(MCoeObserverOfFocusedFepAwareItem& aObserverOfFocusedFepAwareItem)
	{
	__ASSERT_ALWAYS(&aObserverOfFocusedFepAwareItem!=NULL, Panic(ECoePanicIllegalNullParameter2));
	CArrayFix<MCoeObserverOfFocusedFepAwareItem*>* const arrayOfObserversOfFocusedFepAwareItem=iExtra->iArrayOfObserversOfFocusedFepAwareItem;
	for (TInt i=arrayOfObserversOfFocusedFepAwareItem->Count()-1; i>=0; --i)
		{
		if ((*arrayOfObserversOfFocusedFepAwareItem)[i]==&aObserverOfFocusedFepAwareItem)
			{
			arrayOfObserversOfFocusedFepAwareItem->Delete(i);
			break;
			}
		}
	}

EXPORT_C void CCoeEnv::AddObserverOfLoadedFepL(MCoeObserverOfLoadedFep& aObserverOfLoadedFep)
	{
	__ASSERT_ALWAYS(&aObserverOfLoadedFep!=NULL, Panic(ECoePanicIllegalNullParameter13));
	CArrayFix<MCoeObserverOfLoadedFep*>* const arrayOfObserversOfLoadedFep=iExtra->iArrayOfObserversOfLoadedFep;
	for (TInt i=arrayOfObserversOfLoadedFep->Count()-1; i>=0; --i)
		{
		__ASSERT_ALWAYS((*arrayOfObserversOfLoadedFep)[i]!=&aObserverOfLoadedFep, Panic(ECoePanicFocusObserverHasAlreadyBeenAdded));
		}
	arrayOfObserversOfLoadedFep->AppendL(&aObserverOfLoadedFep);
	}

EXPORT_C void CCoeEnv::RemoveObserverOfLoadedFep(MCoeObserverOfLoadedFep& aObserverOfLoadedFep)
	{
	__ASSERT_ALWAYS(&aObserverOfLoadedFep!=NULL, Panic(ECoePanicIllegalNullParameter14));
	CArrayFix<MCoeObserverOfLoadedFep*>* const arrayOfObserversOfLoadedFep=iExtra->iArrayOfObserversOfLoadedFep;
	for (TInt i=arrayOfObserversOfLoadedFep->Count()-1; i>=0; --i)
		{
		if ((*arrayOfObserversOfLoadedFep)[i]==&aObserverOfLoadedFep)
			{
			arrayOfObserversOfLoadedFep->Delete(i);
			break;
			}
		}
	}

EXPORT_C void CCoeEnv::AddFocusObserverL(MCoeFocusObserver& aFocusObserver)
	{
	__ASSERT_ALWAYS(&aFocusObserver!=NULL, Panic(ECoePanicIllegalNullParameter3));
	CArrayFix<MCoeFocusObserver*>* const arrayOfFocusObservers=iExtra->iArrayOfFocusObservers;
	for (TInt i=arrayOfFocusObservers->Count()-1; i>=0; --i)
		{
		__ASSERT_ALWAYS((*arrayOfFocusObservers)[i]!=&aFocusObserver, Panic(ECoePanicFocusObserverHasAlreadyBeenAdded));
		}
	arrayOfFocusObservers->AppendL(&aFocusObserver);
	}

EXPORT_C void CCoeEnv::RemoveFocusObserver(MCoeFocusObserver& aFocusObserver)
	{
	__ASSERT_ALWAYS(&aFocusObserver!=NULL, Panic(ECoePanicIllegalNullParameter4));
	CArrayFix<MCoeFocusObserver*>* const arrayOfFocusObservers=iExtra->iArrayOfFocusObservers;
	for (TInt i=arrayOfFocusObservers->Count()-1; i>=0; --i)
		{
		if ((*arrayOfFocusObservers)[i]==&aFocusObserver)
			{
			arrayOfFocusObservers->Delete(i);
			break;
			}
		}
	}

void CCoeEnv::NotifyFocusObserversOfChangeInFocus()
	{
	CArrayFix<MCoeFocusObserver*>* const arrayOfFocusObservers=iExtra->iArrayOfFocusObservers;
	for (TInt i=arrayOfFocusObservers->Count()-1; i>=0; --i)
		{
		(*arrayOfFocusObservers)[i]->HandleChangeInFocus();
		}
	}

EXPORT_C void CCoeEnv::AddForegroundObserverL(MCoeForegroundObserver& aForegroundObserver)
	{
	__ASSERT_ALWAYS(&aForegroundObserver!=NULL, Panic(ECoePanicIllegalNullParameter5));
	CArrayFix<MCoeForegroundObserver*>* const arrayOfForegroundObservers=iExtra->iArrayOfForegroundObservers;
	for (TInt i=arrayOfForegroundObservers->Count()-1; i>=0; --i)
		{
		__ASSERT_ALWAYS((*arrayOfForegroundObservers)[i]!=&aForegroundObserver, Panic(ECoePanicForegroundObserverHasAlreadyBeenAdded));
		}
	arrayOfForegroundObservers->AppendL(&aForegroundObserver);
	}

EXPORT_C void CCoeEnv::RemoveForegroundObserver(MCoeForegroundObserver& aForegroundObserver)
	{
	__ASSERT_ALWAYS(&aForegroundObserver!=NULL, Panic(ECoePanicIllegalNullParameter6));
	CArrayFix<MCoeForegroundObserver*>* const arrayOfForegroundObservers=iExtra->iArrayOfForegroundObservers;
	for (TInt i=arrayOfForegroundObservers->Count()-1; i>=0; --i)
		{
		if ((*arrayOfForegroundObservers)[i]==&aForegroundObserver)
			{
			arrayOfForegroundObservers->Delete(i);
			break;
			}
		}
	}

void CCoeEnv::NotifyForegroundObserversOfGainingForeground()
	{
	CArrayFix<MCoeForegroundObserver*>* const arrayOfForegroundObservers=iExtra->iArrayOfForegroundObservers;
	for (TInt i=arrayOfForegroundObservers->Count()-1; i>=0; --i)
		{
		(*arrayOfForegroundObservers)[i]->HandleGainingForeground();
		}
	}

void CCoeEnv::NotifyForegroundObserversOfLosingForeground()
	{
	CArrayFix<MCoeForegroundObserver*>* const arrayOfForegroundObservers=iExtra->iArrayOfForegroundObservers;
	for (TInt i=arrayOfForegroundObservers->Count()-1; i>=0; --i)
		{
		(*arrayOfForegroundObservers)[i]->HandleLosingForeground();
		}
	}

EXPORT_C void CCoeEnv::AddFepObserverL(MCoeFepObserver& aFepObserver)
	{
	__ASSERT_ALWAYS(&aFepObserver!=NULL, Panic(ECoePanicIllegalNullParameter7));
	CArrayFix<MCoeFepObserver*>* const arrayOfFepObservers=iExtra->iArrayOfFepObservers;
	for (TInt i=arrayOfFepObservers->Count()-1; i>=0; --i)
		{
		__ASSERT_ALWAYS((*arrayOfFepObservers)[i]!=&aFepObserver, Panic(ECoePanicFepObserverHasAlreadyBeenAdded));
		}
	arrayOfFepObservers->AppendL(&aFepObserver);
	}

EXPORT_C void CCoeEnv::RemoveFepObserver(MCoeFepObserver& aFepObserver)
	{
	__ASSERT_ALWAYS(&aFepObserver!=NULL, Panic(ECoePanicIllegalNullParameter8));
	CArrayFix<MCoeFepObserver*>* const arrayOfFepObservers=iExtra->iArrayOfFepObservers;
	for (TInt i=arrayOfFepObservers->Count()-1; i>=0; --i)
		{
		if ((*arrayOfFepObservers)[i]==&aFepObserver)
			{
			arrayOfFepObservers->Delete(i);
			break;
			}
		}
	}

EXPORT_C void CCoeEnv::ForEachFepObserverCall(TCoeFepObserverFunction aFepObserverFunction)
	{
	CArrayFix<MCoeFepObserver*>* const arrayOfFepObservers=iExtra->iArrayOfFepObservers;
	for (TInt i=arrayOfFepObservers->Count()-1; i>=0; --i)
		{
		(*aFepObserverFunction)(*(*arrayOfFepObservers)[i]);
		}
	}

EXPORT_C CCoeFepParameters* CCoeEnv::FepParameters()
	{
	return iExtra->iFepParameters;
	}

EXPORT_C void CCoeEnv::SetUpFepL(CCoeFepParameters* aFepParameters, const TDesC& aFileNameOfDefaultFepDll)
	{
	__ASSERT_ALWAYS(aFepParameters!=NULL, Panic(ECoePanicIllegalNullParameter3));
	HBufC* fileNameOfDefaultFepDll=aFileNameOfDefaultFepDll.AllocL(); // do this before deleting anything
	delete (CBase*)iExtra->iFepParameters;
	iExtra->iFepParameters=aFepParameters;
	delete iExtra->iFileNameOfDefaultFepDll;
	iExtra->iFileNameOfDefaultFepDll=fileNameOfDefaultFepDll;
	}

void CCoeEnv::LoadFepL()
	{
	__ASSERT_DEBUG((iExtra->iFepParameters!=NULL)==(iExtra->iFileNameOfDefaultFepDll!=NULL), Panic(ECoePanicInconsistentFepState));
	if (iExtra->iFileNameOfDefaultFepDll!=NULL)
		{
		HBufC* fileNameOfFepDll=NULL;
		CDictionaryStore* dictionaryStore=NULL;
		TRAPD(error, dictionaryStore=CDictionaryFileStore::SystemL(iFsSession));
		if (error!=KErrInUse)
			{
			User::LeaveIfError(error);
			CleanupStack::PushL(dictionaryStore);
			const TUid FepNameStreamUid=TUid::Uid(KFepNameStreamUid);
			if (dictionaryStore->IsPresentL(FepNameStreamUid))
				{
				RDictionaryReadStream stream;
				stream.OpenLC(*dictionaryStore, FepNameStreamUid);
				fileNameOfFepDll=HBufC::NewL(stream, KMaxFileName);
				CleanupStack::PopAndDestroy(); // stream
				}
			CleanupStack::PopAndDestroy(); // dictionaryStore - close this before loading the front-end processor so that it can open it if it wants to
			}
		if (fileNameOfFepDll==NULL)
			{
			fileNameOfFepDll=iExtra->iFileNameOfDefaultFepDll->AllocL();
			}
		if (fileNameOfFepDll->Length()==0)
			{
			delete fileNameOfFepDll;
			CCoeEnvExtra::DestroyFep(iExtra->iFep[iExtra->iFepIndex]);
			}
		else
			{
			CleanupStack::PushL(fileNameOfFepDll);
			const TInt newFepIndex=(iExtra->iFepIndex+1)%2;
			CCoeEnvExtra::SFep& newFep=iExtra->iFep[newFepIndex];
			CleanupStack::PushL(TCleanupItem(CCoeEnvExtra::DestroyFep, &newFep));
			User::LeaveIfError(newFep.iFepLibrary.Load(*fileNameOfFepDll, KLitFrontEndProcessorDirectoryName, TUidType(TUid::Uid(0x10000079), KUidFepDll, KNullUid)));
			newFep.iFep=(*(TCoeFepFactoryFunctionL)newFep.iFepLibrary.Lookup(1))(*iExtra->iFepParameters, newFep.iFepLibrary.FileName());
			CleanupStack::Pop(); // TCleanupItem(CCoeEnvExtra::DestroyFep, &newFep)
			CCoeEnvExtra::DestroyFep(iExtra->iFep[iExtra->iFepIndex]);
			iExtra->iFepIndex=newFepIndex;
			CleanupStack::PopAndDestroy(); // fileNameOfFepDll
			}
		CArrayFix<MCoeObserverOfLoadedFep*>* const arrayOfObserversOfLoadedFep=iExtra->iArrayOfObserversOfLoadedFep;
		for (TInt i=arrayOfObserversOfLoadedFep->Count()-1; i>=0; --i)
			{
			(*arrayOfObserversOfLoadedFep)[i]->HandleChangeInLoadedFep();
			}
		}
	}

EXPORT_C MDesCArray* CCoeEnv::FileNamesOfAvailableFepsL()
	{
	CDesCArrayFlat* array=new(ELeave) CDesCArrayFlat(5);
	CleanupStack::PushL(array);
	TFindFile* findFile=new(ELeave) TFindFile(iFsSession);
	CleanupStack::PushL(findFile);
	TParse* fileNameParser=new(ELeave) TParse;
	CleanupStack::PushL(fileNameParser);
	CDir* directory=NULL;
	TInt error=findFile->FindWildByDir(_L("*"), KLitFrontEndProcessorDirectoryName, directory);
	for (; error!=KErrNotFound; error=findFile->FindWild(directory))
		{
		CleanupStack::PushL(directory);
		User::LeaveIfError(error);
		for (TInt i=directory->Count()-1; i>=0; --i)
			{
			const TEntry& entry=(*directory)[i];
			fileNameParser->SetNoWild(entry.iName, &findFile->File(), NULL); // findFile->File() returns a reference rather than an object, therefore taking the address of it is fine
			const TDesC& fileName=fileNameParser->FullName();
#if defined(__WINS__)
			RLibrary library;
			const TInt error=library.Load(fileName, TUidType(TUid::Uid(0x10000079), KUidFepDll, KNullUid));
			library.Close();
			if (error==KErrNone)
#else
			if ((entry.iType[0].iUid==0x10000079) && (entry.iType[1].iUid==KUidFepDll.iUid))
#endif
				{
				array->AppendL(fileName);
				}
			}
		CleanupStack::PopAndDestroy(); // directory
		directory=NULL;
		}
	delete directory;
	CleanupStack::PopAndDestroy(2); // fileNameParser and findFile
	CleanupStack::Pop(); // array
	return array;
	}

EXPORT_C void CCoeEnv::InstallFepL(const TDesC& aFileNameOfFepDll)
	{
	CDictionaryStore* dictionaryStore=CDictionaryFileStore::SystemLC(iFsSession);
	RDictionaryWriteStream stream;
	stream.AssignLC(*dictionaryStore, TUid::Uid(KFepNameStreamUid));
	stream << aFileNameOfFepDll;
	stream.CommitL();
	CleanupStack::PopAndDestroy(); // stream
	dictionaryStore->CommitL();
	CleanupStack::PopAndDestroy(); // dictionaryStore
	iExtra->iFepTracker->FepHasChanged();
	}

EXPORT_C HBufC* CCoeEnv::NameOfInstalledFepL()
	{
	CDictionaryStore* dictionaryStore=CDictionaryFileStore::SystemLC(iFsSession);
	const TUid uid=TUid::Uid(KFepNameStreamUid);
	if (!dictionaryStore->IsPresentL(uid))
		{
		CleanupStack::PopAndDestroy(); // dictionaryStore
		return NULL;
		}
	RDictionaryReadStream stream;
	stream.OpenLC(*dictionaryStore, uid);
	HBufC* fileNameOfFepDll=HBufC::NewL(stream, KMaxFileName);
	CleanupStack::PopAndDestroy(2); // stream and dictionaryStore
	return fileNameOfFepDll;
	}

LOCAL_C void CloseLibrary(TAny* aLibrary)
	{
	((RLibrary*)aLibrary)->Close();
	}

EXPORT_C void CCoeEnv::ExecuteFepSettingsDialogL(const TDesC& aFileNameOfFepDll)
	{
	RLibrary fepLibrary;
	CleanupStack::PushL(TCleanupItem(CloseLibrary, &fepLibrary));
	User::LeaveIfError(fepLibrary.Load(aFileNameOfFepDll, KLitFrontEndProcessorDirectoryName, TUidType(TUid::Uid(0x10000079), KUidFepDll, KNullUid)));
	(*(TCoeSynchronouslyExecuteFepSettingsDialogFunctionL)fepLibrary.Lookup(2))();
	CleanupStack::PopAndDestroy(); // fepLibrary
	}

EXPORT_C CCoeFep* CCoeEnv::Fep() const
	{
	return iExtra->iFep[iExtra->iFepIndex].iFep;
	}

EXPORT_C void CCoeEnv::SetFocusedFepAwareItem(MCoeFepAwareItem* aFocusedFepAwareItem, TCoeFepAwareItemIsFocusedFunction aFepAwareItemIsFocusedFunction)
	{
	__ASSERT_ALWAYS((aFocusedFepAwareItem!=NULL) && (aFepAwareItemIsFocusedFunction!=NULL), Panic(ECoePanicIllegalNullParameter4));
	__ASSERT_ALWAYS((*aFepAwareItemIsFocusedFunction)(*aFocusedFepAwareItem), Panic(ECoePanicIllegalNullParameter5));
	iExtra->iFocusedFepAwareItem=aFocusedFepAwareItem;
	iExtra->iFepAwareItemIsFocusedFunction=aFepAwareItemIsFocusedFunction;
	FocusedFepAwareItemHasChanged();
	}

EXPORT_C void CCoeEnv::FepAwareItemIsNotFocusedOrIsBeingDestroyed(MCoeFepAwareItem* aFepAwareItem)
	{
	__ASSERT_ALWAYS(aFepAwareItem!=NULL, Panic(ECoePanicIllegalNullParameter6));
	if (iExtra->iFocusedFepAwareItem==aFepAwareItem)
		{
		NoFocusedFepAwareItem();
		}
	}

void CCoeEnv::NoFocusedFepAwareItem()
	{
	iExtra->iFocusedFepAwareItem=NULL;
	iExtra->iFepAwareItemIsFocusedFunction=NULL;
	FocusedFepAwareItemHasChanged();
	}

void CCoeEnv::FocusedFepAwareItemHasChanged()
	{
	CArrayFix<MCoeObserverOfFocusedFepAwareItem*>* const arrayOfObserversOfFocusedFepAwareItem=iExtra->iArrayOfObserversOfFocusedFepAwareItem;
	for (TInt i=arrayOfObserversOfFocusedFepAwareItem->Count()-1; i>=0; --i)
		{
		(*arrayOfObserversOfFocusedFepAwareItem)[i]->HandleChangeInFocusedFepAwareItem();
		}
	}

EXPORT_C MCoeFepAwareItem* CCoeEnv::FocusedFepAwareItem() const
	{
	return iExtra->iFocusedFepAwareItem;
	}

TCoeFepAwareItemIsFocusedFunction CCoeEnv::FepAwareItemIsFocusedFunction() const
	{
	__ASSERT_DEBUG(iExtra->iFepAwareItemIsFocusedFunction!=NULL, Panic(ECoePanicNoFepAwareItemIsFocusedFunction));
	return iExtra->iFepAwareItemIsFocusedFunction;
	}

void CCoeEnv::IncrementNumberOfNestedSetFocusCalls()
	{
	__ASSERT_DEBUG(iExtra->iNumberOfNestedSetFocusCalls>=0,Panic(ECoePanicNegativeNumberOfNestedSetFocusCalls1));
	++iExtra->iNumberOfNestedSetFocusCalls;
	}

void CCoeEnv::DecrementNumberOfNestedSetFocusCalls()
	{
	--iExtra->iNumberOfNestedSetFocusCalls;
	__ASSERT_DEBUG(iExtra->iNumberOfNestedSetFocusCalls>=0,Panic(ECoePanicNegativeNumberOfNestedSetFocusCalls2));
	}

TInt CCoeEnv::NumberOfNestedSetFocusCalls() const
	{
	__ASSERT_DEBUG(iExtra->iNumberOfNestedSetFocusCalls>=0,Panic(ECoePanicNegativeNumberOfNestedSetFocusCalls3));
	return iExtra->iNumberOfNestedSetFocusCalls;
	}

EXPORT_C CWindowGc* CCoeEnv::SwapSystemGc(CWindowGc* aGc)
	{
	__ASSERT_ALWAYS(aGc,Panic(ECoePanicNullGc));
	CWindowGc* gc=iSystemGc;
	iSystemGc=aGc;
	return gc;
	}

EXPORT_C void CCoeEnv::Reserved_1()
	{
	}

EXPORT_C void CCoeEnv::Reserved_2()
	{
	}

// MCoeObserverOfFocusedFepAwareItem

EXPORT_C void MCoeObserverOfFocusedFepAwareItem::MCoeObserverOfFocusedFepAwareItem_Reserved_1()
	{
	}

EXPORT_C void MCoeObserverOfFocusedFepAwareItem::MCoeObserverOfFocusedFepAwareItem_Reserved_2()
	{
	}

// MCoeObserverOfLoadedFep

EXPORT_C void MCoeObserverOfLoadedFep::MCoeObserverOfLoadedFep_Reserved_1()
	{
	}

EXPORT_C void MCoeObserverOfLoadedFep::MCoeObserverOfLoadedFep_Reserved_2()
	{
	}

// MCoeFocusObserver

EXPORT_C void MCoeFocusObserver::MCoeFocusObserver_Reserved_1()
	{
	}

EXPORT_C void MCoeFocusObserver::MCoeFocusObserver_Reserved_2()
	{
	}

// MCoeForegroundObserver

EXPORT_C void MCoeForegroundObserver::MCoeForegroundObserver_Reserved_1()
	{
	}

EXPORT_C void MCoeForegroundObserver::MCoeForegroundObserver_Reserved_2()
	{
	}
