windowing/windowserver/nonnga/SERVER/WSTOP.CPP
changeset 0 5d03bc08d59c
child 116 171fae344dd4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/WSTOP.CPP	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,1042 @@
+// Copyright (c) 1994-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:
+// Top level window server code
+// 
+//
+
+#include "wstop.h"
+
+#include <hal.h>
+#include "ANIM.H"
+#include "gc.h"
+#include "playbackgc.h"
+#include "rootwin.h"
+#include "windowgroup.h"
+#include "EVENT.H"
+#include "KEYCLICK.H"
+#include <w32std.h>
+#include "offscreenbitmap.h"
+#include "panics.h"
+#include "inifile.h"
+#include "pointer.h"
+#include "WSGRAPHICDRAWERFACTORY.H"
+#include "redrawmsgwindow.h"
+#include <Graphics/WSGRAPHICDRAWERINTERFACE.H>
+#include "WsMemMgr.h"
+#include "backedupwindow.h"
+#include "wsfont.h"
+#include "wstraces.h"
+#ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP
+#include <e32power.h>
+#endif
+#include "graphics/windowserverconstants.h"
+
+typedef CDebugLogBase *(*CreateDebugLog)(TBool aIsFirst, TDesC &aParams);
+
+CWsActiveScheduler* CWsActiveScheduler::Static()
+	{
+	return static_cast<CWsActiveScheduler*>(CActiveScheduler::Current());
+	}
+	
+CWsActiveScheduler::CWsActiveScheduler(): iNumSamples(100)
+	{
+	iRun = User::FastCounter();
+	if((KErrNone == HAL::Get(HALData::EFastCounterFrequency,iFastCounterFreq)) && iFastCounterFreq)
+		{
+		iData = reinterpret_cast<TSample*>(User::AllocZ(sizeof(TSample)*iNumSamples));
+		}
+	}
+
+CWsActiveScheduler::~CWsActiveScheduler()
+	{
+	User::FreeZ(reinterpret_cast<void*&>(iData));
+	}
+	
+void CWsActiveScheduler::PrepareDraw()
+	{
+	WS_ASSERT_DEBUG((ENormal == iState)||(EDrawn == iState),EWsPanicActiveScheduler);
+	__DEBUG_ONLY(iState = EPreparingDraw;)
+	iRunDraw = User::FastCounter();
+	}
+	
+void CWsActiveScheduler::CancelPrepare()
+	{
+	WS_ASSERT_DEBUG(EPreparingDraw == iState,EWsPanicActiveScheduler);
+	__DEBUG_ONLY(iState = ENormal;)
+	}
+	
+void CWsActiveScheduler::StartDraw()
+	{
+	WS_TRACE_SERVER_STARTDRAW();
+	WS_ASSERT_DEBUG(EPreparingDraw == iState,EWsPanicActiveScheduler);
+	__DEBUG_ONLY(iState = EDrawing;)
+	TTime now;
+	now.UniversalTime();
+	TUint64 duration = now.MicroSecondsFrom(iRunDraw).Int64();
+	iPreparing += duration;
+	iRunDraw = now;
+	if(iData)
+		{
+		iData[iCurrent].iStart = iRunDraw;
+		}
+	iDraws++;
+	}
+
+void CWsActiveScheduler::DrawStats(TInt& aUpdatesPerSecond,TInt64& aPixelsPerSecond,TInt aWindowInSeconds) const
+	{
+	aUpdatesPerSecond=0;
+	aPixelsPerSecond=0;
+	if(iData)
+		{
+		// work out statistic
+		TTime window;
+		window.UniversalTime();
+		window-=TTimeIntervalSeconds(aWindowInSeconds);
+		TUint32 pixels=0;
+		TInt64 duration=0;
+		for(TInt ii=0;ii<iNumSamples;++ii)
+			{
+			if (iData[ii].iStart>=window)
+				{
+				pixels+=iData[ii].iPixels;
+				duration+=iData[ii].iDuration;
+				++aUpdatesPerSecond;
+				}
+			}
+		if (aUpdatesPerSecond && duration)
+			{
+			aPixelsPerSecond=pixels;
+			aPixelsPerSecond=(aPixelsPerSecond*1000000)/duration;
+			aUpdatesPerSecond/=aWindowInSeconds;
+			}
+		}
+	}
+
+void CWsActiveScheduler::StopDraw(TInt aPixelsUpdated)
+	{
+	WS_TRACE_SERVER_STOPDRAW();
+	WS_ASSERT_DEBUG(EDrawing == iState,EWsPanicActiveScheduler);
+	__DEBUG_ONLY(iState = EDrawn;)
+	TTime now;
+	now.UniversalTime();
+	TUint32 duration = now.MicroSecondsFrom(iRunDraw).Int64();
+    // do recording
+	if(iData)
+		{
+		iData[iCurrent].iDuration = now.MicroSecondsFrom(iData[iCurrent].iStart).Int64();
+		iData[iCurrent].iPixels = aPixelsUpdated;
+		if(++iCurrent >= iNumSamples)
+			{
+			iCurrent = 0;
+			}
+		}
+	iDrawing += duration;
+	}
+
+void CWsActiveScheduler::WaitForAnyRequest()
+	{
+	WS_ASSERT_DEBUG((ENormal == iState)||(EDrawn == iState),EWsPanicActiveScheduler);
+	TTime stop;
+	stop.UniversalTime();
+	iTotal += stop.MicroSecondsFrom(iRun).Int64();
+	CActiveScheduler::WaitForAnyRequest();
+	iRequests++;
+	__DEBUG_ONLY(iState = ENormal;)
+	iRun.UniversalTime();
+	iIdle += iRun.MicroSecondsFrom(stop).Int64();
+	}
+
+	
+void CWsActiveScheduler::Error(TInt /*aError*/) const
+	{
+	iErrors++;
+	}
+
+void CWsActiveScheduler::AccumReclaimedIdleTime(TInt64 aMicroSeconds)
+	{
+	iReclaimedIdleTime += aMicroSeconds;
+	}
+	
+
+GLREF_C void StateDump(CWsRootWindow* aRootWindow);
+GLREF_C void HeapDump();
+
+// Static objects that need to be destroyed on exit
+GLDEF_D CDebugLogBase *wsDebugLog=NULL;
+GLDEF_D TInt wsDebugLogLevel=0;
+GLDEF_D CIniFile *WsIniFile=NULL;
+//
+GLDEF_D TPtr nullDescriptor(NULL,0);
+
+LOCAL_D CWsActiveScheduler *TheActiveScheduler;
+#if defined(__WINS__)
+LOCAL_D TPtrC shellCmd;
+#endif
+
+CScreen* CWsTop::iCurrentFocusScreen;
+CArrayPtrFlat<CScreen>* CWsTop::iScreens ;
+TInt CWsTop::iNumberOfScreens ;
+CWsTop::CShellStarter* CWsTop::iShellStarter;
+
+CWindowServer *CWsTop::iServer;
+RLibrary CWsTop::iDebugLib;
+CWsShellLogon *CWsTop::iShell;
+const CWsClient *CWsTop::iShellClient;
+TBool CWsTop::iPreviousShellClient=EFalse;
+TInt CWsTop::iShellBootMode;
+TBool CWsTop::iShuttingDown;
+TBool CWsTop::iIsFirstLog=ETrue;
+CWsWindowBase *CWsTop::iWindowToSendOffEventsTo=NULL;
+RTimer CWsTop::iTimer;
+TBool CWsTop::iIgnoreSwitchOffEvent=EFalse;
+TBool CWsTop::iFadeEnabled=ETrue;
+TBool CWsTop::iFinishEveryFlush=EFalse;
+TBool CWsTop::iMultiFocusPolicy=EFalse;
+#if defined(__WINS__)
+TFullName WsSemName;
+#endif
+const CWsClient* CWsTop::iTriggerHeapCheckOnClientExit=NULL;
+TWsCheckHeapOnDisconnectMode CWsTop::iHeapCheckMode=EWsCheckHeapOnDisconnectModeNone;
+TInt CWsTop::iCheckHeapResult=KErrNotReady;
+TBool CWsTop::iDoHeapCheckAndRestart=EFalse;
+#define RFbsSession_SendCommand_ShutDownMessage 1	// A FBS message that is not published yet and probably never will be.
+void CWsTop::DeleteStaticsL()
+	{
+	iShuttingDown=ETrue;
+	CClick::DeleteStatics();
+	WsPointer::DeleteStatics();
+	CWsClient::DeleteStatics();
+//
+	delete iShellStarter;
+	delete iServer;
+
+	CWsBackedUpWindow::StaticDestroy();
+	TWindowServerEvent::DeleteStatics();
+	delete iShell;
+	DisableLogging();
+
+	CEventQueue::DeleteStaticsL();
+		
+	CWsSpriteBase::DeleteStatics();
+	CWsGc::DeleteStatics();
+	CPlaybackGc::DeleteStatics();
+	CWsAnim::DeleteStatics();		//This destroys a GC so must be done while FBSERV is still around
+	CWsAnimDll::DeleteStatics();
+	CWsFontCache::DestroyInstance();
+
+	iScreens->ResetAndDestroy() ;
+	delete iScreens ;
+
+	if (!iDoHeapCheckAndRestart)
+		{
+		RFbsSession::GetSession()->SendCommand(RFbsSession_SendCommand_ShutDownMessage);		//This line is just being tidy, never really does anything useful.
+		}
+
+	RFbsSession::Disconnect();
+	iDebugLib.Close();
+	iTimer.Close();
+//
+	delete WsIniFile;
+	delete TheActiveScheduler;
+	WsGraphicDrawer::FinalClose();
+	}
+
+RWsTextCursor *CWsTop::CurrentTextCursor()
+	{
+	return(FocusWindowGroup() ? FocusWindowGroup()->TextCursor():NULL);
+	}
+
+CWsClient *CWsTop::FocusWindowGroupOwner()
+	{
+	return(FocusWindowGroup() ? FocusWindowGroup()->WsOwner():NULL);
+	}
+
+void CWsTop::ClientDestroyed(const CWsClient *aClient)
+	{
+	if (aClient==iShellClient)
+		iShellClient=NULL;
+	}
+
+void CWsTop::NewSession(const CWsClient *aClient)
+	{
+	if (iShellClient==NULL && iShell)
+		{
+#if defined(__WINS__)
+		RThread proc;
+		proc=aClient->Client();
+#else
+		RProcess proc;
+		aClient->Client().Process(proc);
+#endif
+		TFullName procName = proc.FullName();
+		// Before comparing the proc name with iShell name , truncate the proc name up to the actual name
+		// referring to the process, by removing the part which starts with ':', if exists.
+		TInt colonLocation = procName.Locate(':');
+		if( KErrNotFound != colonLocation)
+			{
+			procName = procName.Left(colonLocation);
+			}
+		if (procName ==iShell->FullName())
+			{
+			iShellClient=aClient;
+			if (!iPreviousShellClient)
+				{
+				iPreviousShellClient=ETrue;
+				aClient->Screen()->RootWindow()->SetColorIfClear();
+				}
+			}
+#if !defined(__WINS__)
+		proc.Close();
+#endif
+		}	
+	}
+
+void CWsTop::SessionExited(CWsClient *aClient)
+	{
+	if (iShuttingDown)
+		{
+		RProcess proc;
+		TInt err=aClient->Client().Process(proc);
+		if (err==KErrNone && proc.Id()!=RProcess().Id())
+			proc.Kill(0);
+		else
+			const_cast<RThread&>(aClient->Client()).Kill(0);
+		if (err==KErrNone)
+			proc.Close();
+		}
+	else if (iHeapCheckMode!=EWsCheckHeapOnDisconnectModeNone && aClient==iTriggerHeapCheckOnClientExit)
+		{
+		if (iHeapCheckMode==EWsCheckHeapOnDisconnectModeOnce)
+			{
+			iHeapCheckMode=EWsCheckHeapOnDisconnectModeNone;
+			}
+		iTriggerHeapCheckOnClientExit=NULL;
+		iDoHeapCheckAndRestart=ETrue;
+		Exit();
+		}
+	if (iServer->SessionCount()==1 && iShellBootMode==EShellBootModeNoReboot && iShell==NULL)
+		StartShell();
+	}
+
+
+void CWsTop::RunServerL()
+	{
+	InitStaticsL();
+	CWsMemoryManager* memMgr = CWsMemoryManager::NewLC();
+	CActiveScheduler::Start();
+	CleanupStack::PopAndDestroy(memMgr);
+	DeleteStaticsL();
+	}
+
+void CWsTop::InitStaticsL()
+	{
+	iShuttingDown=EFalse;
+	// By default shell should be started.
+	TBool startShell = ETrue;
+
+	// The windows server has been invoked.
+	// This may have been from the system starter (via a
+	// start up rss file)  
+	// This block looks for a "-NoShell" argument in the invocation.
+	// The existence of the argument means that shell does not need to be 
+	// invoked from here because the new system starter
+	// is in charge, and it will do it if required.
+	
+	_LIT(KNoShell,"-NOSHELL");
+	
+	TInt argLen = User::CommandLineLength();
+	if(argLen)
+		{
+		HBufC* arg = HBufC::NewLC(argLen);
+		TPtr argPtr = arg->Des();
+		User::CommandLine(argPtr);
+		argPtr.UpperCase();
+
+		if(KErrNotFound != argPtr.Find(KNoShell))
+			{
+			// Don't start the shell. It will be started if required by 
+			// the system starter.
+			startShell = EFalse;
+			}
+		CleanupStack::PopAndDestroy(arg);
+		}
+		
+	TheActiveScheduler=new(ELeave) CWsActiveScheduler;
+	CActiveScheduler::Install(TheActiveScheduler);
+	
+//
+	WsIniFile=CIniFile::NewL();
+	_LIT(KWSERVIniFileVarLogEnable,"LOGENABLE");
+	TInt loggingLevel;
+	if (WsIniFile->FindVar(KWSERVIniFileVarLogEnable,loggingLevel))
+		{
+		EnableLogging(EDoNotReloadWsIni);
+		if (wsDebugLog)
+			{
+			wsDebugLog->SetLoggingLevel(loggingLevel);
+			}
+		}
+		
+	_LIT(KWSERVIniFileVarFadeEnable,"FADEDISABLE");
+	iFadeEnabled = !WsIniFile->FindVar(KWSERVIniFileVarFadeEnable);
+
+	_LIT(KWSERVIniFileVarFinishEveryFlush,"FINISHEVERYFLUSH");
+	iFinishEveryFlush = WsIniFile->FindVar(KWSERVIniFileVarFinishEveryFlush);
+	
+	_LIT(KWSERVIniFileVarSwitchOffEvent,"IGNORESWITCHOFFEVENT");
+	iIgnoreSwitchOffEvent = WsIniFile->FindVar(KWSERVIniFileVarSwitchOffEvent);	
+
+	iServer=CWindowServer::NewL();
+	CClick::InitStaticsL();
+	
+	RProcess wservProc;
+	if (!wservProc.DefaultDataPaged())
+	{
+		iServer->SetPinClientDescriptors(ETrue);
+	}
+//
+	iServer->StartL(KWSERVServerName);
+//
+	User::LeaveIfError(FbsStartup());
+	User::LeaveIfError(RFbsSession::Connect());
+	User::LeaveIfError(iTimer.CreateLocal());
+
+	TWindowServerEvent::InitStaticsL();
+	//-------------------------------------------
+	User::LeaveIfError(  HAL::Get( HAL::EDisplayNumberOfScreens, iNumberOfScreens ) ) ; 
+	// Check that the INI file matches the HAL
+	WS_ASSERT_ALWAYS(WsIniFile->NumberOfScreens()<=iNumberOfScreens, EWsPanicScreenInformationError);
+
+	iScreens = new (ELeave) CArrayPtrFlat<CScreen>( iNumberOfScreens ) ;  //
+	// now construct screens for as long as there is information
+	
+	TInt ii ;
+	for ( ii = 0 ; ii < iNumberOfScreens ; ++ii )
+		{
+		InitScreenL( ii ) ;
+		}
+	//---------------------------------------------
+	iCurrentFocusScreen = (*iScreens)[0] ;
+
+	CWsFontCache::CreateInstanceL();
+	CWsGc::InitStaticsL();
+	CPlaybackGc::InitStaticsL();
+	CWsSpriteBase::InitStaticsL();
+	CEventQueue::InitStaticsL();
+
+//
+	CWsAnimDll::InitStaticsL();
+	CWsAnim::InitStaticsL();
+//
+	TInt bootMode=0;
+	_LIT(KWSERVIniFileVarReboot,"REBOOT");
+	WsIniFile->FindVar(KWSERVIniFileVarReboot,bootMode);
+	if (bootMode>=0 && bootMode<=2)
+		iShellBootMode=bootMode;
+//
+	CWsBackedUpWindow::StaticInitL();
+	CWsRedrawMsgWindow::StaticInitL();
+//
+	WsPointer::InitStaticsL();
+	iShellStarter=new (ELeave) CShellStarter;
+	iShellStarter->ConstructL();
+	_LIT(KPreProcess,"REMOVEFADINGONFOCUSGAIN");
+	CWsWindowGroup::SetFocusGainPreprocessing(WsIniFile->FindVar(KPreProcess));
+	_LIT(KAbsFade,"ABSOLUTEFADING");
+	CWsClientWindow::SetAbsoluteFading(WsIniFile->FindVar(KAbsFade));
+
+//Set the focus policy
+	_LIT(KFocusPolicy,"MULTIFOCUSPOLICY");
+	if(WsIniFile->FindVar(KFocusPolicy))
+		{
+		iMultiFocusPolicy = ETrue;	
+		}
+	RProcess::Rendezvous(KErrNone);
+	// Start the shell from here unless the 'NoShell' option has been 
+	// received indicating that the system starter will start the shell directly.
+	if(startShell)
+		{
+		StartShell();
+		}
+	UserSvr::WsRegisterSwitchOnScreenHandling(ETrue);
+	}
+
+
+void CWsTop::InitScreenL( TInt aScreenNumber)  // static
+	{
+	// create a new screen,  read ini file for aScreenNumber (this happens in CScreen - just need to pass a screen number from here
+	CScreen* screen = new (ELeave) CScreen() ;
+	CleanupStack::PushL( screen ) ;
+	TRect digitiserArea;
+	if (aScreenNumber==0)
+		{
+		TMachineInfoV1Buf machineBuf;
+		UserHal::MachineInfo(machineBuf);
+		TMachineInfoV1& machineInfo=*(TMachineInfoV1*)machineBuf.Ptr();
+		digitiserArea = TRect(-machineInfo.iOffsetToDisplayInPixels,machineInfo.iXYInputSizeInPixels);
+		}
+	screen->ConstructL(digitiserArea, aScreenNumber);
+	iScreens->AppendL( screen ) ; 
+	CleanupStack::Pop( screen ) ;
+	}
+
+void CWsTop::UpdateAllScreens()
+	{
+	TInt ii;
+	for (ii=0; ii<iNumberOfScreens; ++ii)
+		{
+		(*iScreens)[ii]->Update();
+		}
+	}
+
+void CWsTop::ClearAllRedrawStores()
+	{
+	TInt ii;
+	for (ii=0; ii<iNumberOfScreens; ++ii)
+		{
+		CScreen *screen=(*iScreens)[ii];
+		CWsWindowGroup* group=screen->RootWindow()->Child();
+		while (group!=NULL)
+			{
+			CWsWindowBase* win=group->Child();
+			if (win)
+				{
+				while (win!=group)
+					{
+					static_cast<CWsWindow*>(win)->Redraw()->ClearRedrawStore(ETrue);
+					if (win->BaseChild())
+						win=win->BaseChild();
+					else
+						{
+						do	
+							{
+							if (win->NextSibling())
+								{
+								win=win->NextSibling();
+								break;
+								}
+							win=win->BaseParent();
+							}
+						while (win!=group);
+						}
+					}
+				}
+			group=group->NextSibling();
+			}
+		TriggerRedraws(screen->RootWindow());
+		}
+	}
+
+void CWsTop::Exit()
+	{
+	CActiveScheduler::Stop();
+	}
+
+void CWsTop::TriggerRedraws(CWsRootWindow* aRootWindow)
+	{
+	for(CWsWindowGroup *group=aRootWindow->Child();group!=NULL;group=group->NextSibling())
+		group->WsOwner()->TriggerRedraw();
+	}
+
+void CWsTop::StartShell()
+	{
+	TRAPD(err,iShell=new(ELeave) CWsShellLogon());
+	if (err==KErrNone)
+		{
+		RFs fs;
+		if ((err=fs.Connect())==KErrNone)
+			{
+			fs.SetNotifyUser(EFalse);
+			TRAP(err,iShell->ConstructL(fs));
+			fs.Close();
+			}
+		}
+	if (err!=KErrNone)
+		{
+#ifdef _DEBUG
+		RDebug::Print(_L("Failed to start shell: err=%d\n"),err);
+#endif
+		delete iShell;
+		iShell=NULL;
+		iShellStarter->After(TTimeIntervalMicroSeconds32(1000000));
+		}
+	}
+
+void CWsTop::ShellExited()
+	{
+	delete iShell;
+	iShell=NULL;
+	switch(iShellBootMode)
+		{
+		case EShellBootModeReboot:
+			StartShell();
+			break;
+		case EShellBootModeNoReboot:
+			if (iServer->SessionCount()==0)
+				StartShell();
+			break;
+		case EShellBootModeExit:
+			Exit();
+			break;
+		}
+	}
+
+TInt CWsTop::SetSendOffEventsToShell(CWsClient *aClient,const TWsClCmdOffEventsToShell &aData)
+	{
+	CWsWindowBase *window=NULL;
+	if (aData.window==0)
+		{
+		if (aData.on)
+			aClient->PPanic(EWservPanicNoWindowSpecifed);
+		}
+	else
+		aClient->HandleToWindow(aData.window,&window);
+	if (aData.on)
+		{
+		if (iWindowToSendOffEventsTo!=NULL && aClient!=iShellClient)		//Allow the shell to pinch it
+			return KErrAlreadyExists;
+		iWindowToSendOffEventsTo=window;
+		}
+	else
+		{
+		if (iWindowToSendOffEventsTo==window || (!window && aClient==iWindowToSendOffEventsTo->WsOwner()))
+			iWindowToSendOffEventsTo=NULL;
+		}
+	return KErrNone;
+	}
+
+void CWsTop::StopWindowGettingOffEvents(CWsWindowBase* aWindow)
+	{
+	if (aWindow==iWindowToSendOffEventsTo)
+		iWindowToSendOffEventsTo=NULL;
+	}
+
+/** Routes "Off" events to the shutdown manager if one is registered. Othwerwise calls Power API's directly to
+set the power mode of the device accordingly.
+@internalTechnology
+@released
+@param aEvent Type of event that Wserv passes to client as OFF events. 
+It can be EEventSwitchOff, EEventCaseClosed, EEventKeySwitchOff or EEventRestartSystem.
+@param aDoSwitchOff ETrue if the switch-off should be performed when no shutdown manager is registered
+and IGNORESWITCHOFFEVENT is not defined in wsini.ini
+*/
+void CWsTop::HandleSwitchOff(TInt aEvent,TBool aDoSwitchOff)
+	{
+	// If any shutdown manager is registered, forward the event to it
+	if (iWindowToSendOffEventsTo && iWindowToSendOffEventsTo->QueueEvent(aEvent))
+		return;
+	// Otherwise, do the shutdown here
+	if(!iIgnoreSwitchOffEvent && aDoSwitchOff)
+		{
+#ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP		
+		// if LaF is not registered, restart or shutdown using Power API 
+		if (aEvent == EEventRestartSystem) // restart
+			{
+			if (Power::EnableWakeupEvents(EPwRestart) == KErrNone)
+				{
+				// Should reboot/power-cycle the system, so no need to RequestWakeupEventNotification
+				Power::PowerDown();
+				}
+			}
+		else // everything else maps to standby for now
+			{
+			if (Power::EnableWakeupEvents(EPwStandby) == KErrNone)
+				{
+				// Prepare to wake up from standby
+				TRequestStatus s;
+				Power::RequestWakeupEventNotification(s);
+				Power::PowerDown();
+				User::WaitForRequest(s);
+				}
+			}
+#else
+		UserHal::SwitchOff();
+#endif			
+		}
+	}
+
+void CWsTop::RedrawScreens()
+	{
+	// apply to all screens
+	TInt screenNo;
+	for(screenNo=0; screenNo<iNumberOfScreens; ++screenNo)
+		{
+		CScreen* screen = Screen(screenNo);
+		TRegionFix<1> screenArea(TRect(screen->DrawableArea()));
+		screen->Update(screenArea);
+		}
+	}
+
+void CWsTop::EnableLogging(TReloadWsIni aSetting)
+	{
+	TInt errorLoc=0;
+	if (wsDebugLog)
+		{
+		if (wsDebugLogLevel==CDebugLogBase::ELogEverything)
+			{
+			wsDebugLogLevel=CDebugLogBase::ELogImportant;
+			wsDebugLog->SetLoggingLevel(wsDebugLogLevel);
+			return;
+			}
+		DisableLogging();
+		}
+
+     if (aSetting == EDoReloadWsIni)
+        {
+        CIniFile* temp = NULL;
+        TRAPD(err, temp = CIniFile::NewL());
+        if (err == KErrNone)
+            {
+            //loading successful, replace the previous one
+            delete WsIniFile;
+            WsIniFile = temp;
+            }
+        }
+
+	TPtrC dlog;
+	_LIT(KWSERVDebugLogFileName,"DLOG");
+	TBuf<KMaxFileName> fname(KWSERVDebugLogFileName);
+	_LIT(KWSERVIniFileVarLog,"LOG");
+	if (WsIniFile->FindVar(KWSERVIniFileVarLog,dlog) && dlog.Length()==2)
+		{
+		fname.Append(dlog);
+		TInt err=iDebugLib.Load(fname);
+		if (err==KErrNone)
+			{
+			TUidType uid=iDebugLib.Type();
+			if (uid[1]!=KWservLoggingDllUid)
+				{
+				err=KErrNotSupported;
+				errorLoc=2;
+				}
+			else
+				{
+				TPtrC params;
+				_LIT(KWSERVIniFileVarLogP,"LOGP");
+				if (!WsIniFile->FindVar(KWSERVIniFileVarLogP,params))
+					params.Set(NULL,0);
+				CreateDebugLog func=(CreateDebugLog)iDebugLib.Lookup(1);
+				if (func!=NULL)
+					{
+					TRAP(err,wsDebugLog=(*func)(iIsFirstLog, params));
+					if (err==KErrNone)
+						{
+						iIsFirstLog=EFalse;
+						wsDebugLogLevel=CDebugLogBase::ELogEverything;
+						}
+					else
+						errorLoc=4;
+					}
+				else
+					errorLoc=3;
+				}
+			}
+		else
+			errorLoc=1;
+		if (iCurrentFocusScreen)
+			{
+			TWindowServerEvent::ProcessErrorMessages(TWsErrorMessage::ELogging,(errorLoc<<8)-err);
+			}
+		}
+	}
+
+void CWsTop::DisableLogging()
+	{
+	delete wsDebugLog;
+	wsDebugLog=NULL;
+	iDebugLib.Close();
+	}
+
+void CWsTop::LogCommand(RWsSession::TLoggingCommand aCommand)
+	{
+	switch(aCommand)
+		{
+	case RWsSession::ELoggingEnable:
+		EnableLogging();
+		break;
+	case RWsSession::ELoggingDisable:
+		DisableLogging();
+		break;
+	case RWsSession::ELoggingStatusDump:
+		StateDump();
+		break;
+	case RWsSession::ELoggingHeapDump:
+		HeapDump();
+		break;
+		}
+	}
+
+void CWsTop::StateDump()
+	{
+	TInt screenNo;
+	for (screenNo=0; screenNo<iNumberOfScreens; ++screenNo)
+		::StateDump( (*iScreens)[screenNo]->RootWindow());
+	}
+	
+void CWsTop::SetCurrentFocusScreen(CScreen* aScreen)	
+	{
+	iCurrentFocusScreen = aScreen;
+	}
+
+TInt CWsTop::SetCurrentFocusScreen(TInt aScreenNo)
+	{
+	CScreen* newFocusScreen=CWsTop::Screen(aScreenNo);
+	if (newFocusScreen==iCurrentFocusScreen)
+		return KErrNone;
+
+	CWsWindowGroup* newFocusGroup=newFocusScreen->FocusWindowGroup();
+	if (!newFocusGroup)
+		return KErrNotReady;
+
+	CWsWindowGroup* oldFocusGroup=iCurrentFocusScreen->FocusWindowGroup();
+	if (oldFocusGroup)
+		oldFocusGroup->LostFocus();
+	iCurrentFocusScreen=newFocusScreen;
+	newFocusGroup->ReceivedFocus();
+	WsPointer::UpdatePointerCursor();
+	TWindowServerEvent::SendFocusChangedEvents();
+	return KErrNone;
+	}
+
+void CWsTop::SetCheckHeapOnDisconnectClient(const CWsClient* aClient)
+	{
+	iTriggerHeapCheckOnClientExit=aClient;
+	}
+
+void CWsTop::SetCheckHeapOnDisconnectMode(TWsCheckHeapOnDisconnectMode aCheckHeapOnDisconnectMode)
+	{
+	iHeapCheckMode=aCheckHeapOnDisconnectMode;
+	}
+
+TBool CWsTop::NeedsHeapCheckAndRestart(TInt aStartHeapCount)
+	{
+	if (!iDoHeapCheckAndRestart)
+		return(EFalse);
+	iDoHeapCheckAndRestart=EFalse;
+	iCheckHeapResult=User::Heap().Count()-aStartHeapCount;
+	if(iCheckHeapResult > 0)
+	    {
+        const TUint32 orphanedCell = User::Heap().__DbgMarkEnd(aStartHeapCount);
+        RDebug::Printf("Memory leak detected in wserv. First orphaned cell: 0x%8x", orphanedCell);
+        }
+	return(ETrue);;
+	}
+
+TInt CWsTop::FetchCheckHeapResult()
+	{
+	TInt ret=iCheckHeapResult;
+	iCheckHeapResult=KErrNotReady;
+	return(ret);
+	}
+
+/**
+This function looks for memory which isn't essential to the correct running of the window server
+and frees some of it.
+Returns true if some memory was freed, and false if it was unable to free anything.
+Called from the memory manager in low memory conditions.
+*/
+TBool CWsTop::ReleaseMemory()
+	{
+	return iServer->ReleaseMemory();
+	}
+	
+TBool CWsTop::MultiFocusPolicy()
+	{
+	return	iMultiFocusPolicy;
+	}
+	
+typedef TInt (*ShellEntryPoint)(TAny *);
+
+#if defined(__WINS__)
+LOCAL_D const TUint KHeapSize=0x10000;
+LOCAL_D const TUint KMaxHeapSize=0x400000;
+#endif
+
+CWsShellLogon::CWsShellLogon() : CActive(EWsShellLogonPriority)
+	{
+#if defined (__WINS__)
+	// Clear handles to NULL so we can later detect which one gets used
+	iShellThread.SetHandle(NULL);
+	iShellProcess.SetHandle(NULL);
+#endif
+	}
+
+CWsShellLogon::~CWsShellLogon()
+	{
+	Cancel();
+#if defined (__WINS__)
+	iShellThread.Close();
+	iShellProcess.Close();
+#else
+	iShell.Close();
+#endif
+#if defined(__WINS__)
+	iLib.Close();
+#endif
+	}
+
+void CWsShellLogon::ConstructL(RFs &)
+	{
+	CActiveScheduler::Add(this);
+#if !defined(__WINS__)
+	TPtrC shellCmd;
+#endif
+	_LIT(KWSERVIniFileVarShellCmd,"SHELLCMD");
+	WsIniFile->FindVar(KWSERVIniFileVarShellCmd,shellCmd);
+	_LIT(KWSERVShellName,"SHELL");
+	TPtrC startUp(KWSERVShellName);
+	_LIT(KWSERVIniFileVarStartUp,"STARTUP");
+	WsIniFile->FindVar(KWSERVIniFileVarStartUp,startUp);
+
+
+	TParse fileName;
+	_LIT(KWSERVArmShellLocationPattern,"Z:\\sys\\bin\\.EXE");
+	User::LeaveIfError(fileName.SetNoWild(startUp,&KWSERVArmShellLocationPattern,NULL));
+#if defined(__WINS__)
+	TInt err=iShellProcess.Create(fileName.FullName(),shellCmd);
+	if (err == KErrNone)
+		{
+		Request();
+		iShellProcess.Resume();
+		}
+	else
+		{
+		// Try loading the matching DLL name instead?
+		_LIT(KWSERVShellExtension,"Z:.DLL");
+		User::LeaveIfError(fileName.Set(KWSERVShellExtension,&startUp,NULL));
+		User::LeaveIfError(iLib.Load(fileName.FullName()));
+		ShellEntryPoint libFunc=(ShellEntryPoint)iLib.Lookup(1);
+		if (!libFunc)
+			User::Leave(KErrGeneral);
+		TBuf<256> name;
+		TInt num=0;
+		TInt ret=KErrNone;
+		do
+			{
+			_LIT(KWSERVWinsShellInstanceName,"Shell%d");
+			name.Format(KWSERVWinsShellInstanceName,num++);
+			ret=iShellThread.Create(name,libFunc,KDefaultStackSize,&shellCmd,&iLib,NULL,KHeapSize,KMaxHeapSize,EOwnerProcess);
+			} while(ret==KErrAlreadyExists);
+		User::LeaveIfError(ret);
+		Request();
+		iShellThread.Resume();
+		}
+#else // not __WINS__
+	User::LeaveIfError(iShell.Create(fileName.FullName(),shellCmd));
+	Request();
+	iShell.Resume();
+#endif	
+	return;
+
+	}
+
+void CWsShellLogon::DoCancel()
+	{
+#if defined (__WINS__)
+	if(iShellThread.Handle())
+		iShellThread.LogonCancel(iStatus);
+	else
+		iShellProcess.LogonCancel(iStatus);
+#else
+	iShell.LogonCancel(iStatus);
+#endif
+	}
+
+void CWsShellLogon::RunL()
+	{
+	if (iStatus.Int()!=KErrCancel)
+		CWsTop::ShellExited();
+	}
+
+void CWsShellLogon::Request()
+	{
+#if defined (__WINS__)
+	if(iShellThread.Handle())
+		iShellThread.Logon(iStatus);
+	else
+		iShellProcess.Logon(iStatus);
+#else
+	iShell.Logon(iStatus);
+#endif
+	SetActive();
+	}
+
+#if defined(__WINS__) 
+TFullName CWsShellLogon::FullName()
+	{
+	if(iShellThread.Handle())
+		return(iShellThread.FullName());
+	else
+		return(iShellProcess.FullName());
+	}
+#else
+TFullName CWsShellLogon::FullName()
+	{return(iShell.FullName());}
+#endif
+
+
+
+TInt E32Main()
+	{
+	__UHEAP_MARK;
+
+	UserSvr::WsRegisterThread();
+
+	RThread thread;
+	// Set wserv's main thread to system permanent
+	TInt err;
+	err = User::SetCritical(User::ESystemPermanent);
+	if (err!=KErrNone)
+		{
+		WS_PANIC_ALWAYS(EWsPanicFailedToSetThread);
+		}
+// If in the future wserv becomes multi-threaded,
+// we can uncomment the following lines to set any new threads to be system permanent as well.
+//	err = User::SetProcessCritical(User::ESystemPermanent); 
+//	if (err!=KErrNone)
+//		{
+//		WS_PANIC_ALWAYS(EWsPanicFailedToSetProcess);
+//		}
+
+	thread.SetPriority(EPriorityMore);
+	err = User::RenameThread(KWSERVThreadName);
+	if (err==KErrNone)
+		{
+		thread.Close();
+		}
+	else
+		{
+		return err;
+		}
+	TInt startCount;
+	do
+		{
+		User::Heap().__DbgMarkStart();
+		startCount=User::Heap().Count();
+		CTrapCleanup* CleanUpStack=CTrapCleanup::New();
+		TRAP(err,CWsTop::RunServerL());
+		if (err!=KErrNone)
+			{
+			WS_PANIC_ALWAYS(EWsPanicFailedToInitialise);
+			}
+		UserSvr::ReleaseEventHook();
+		delete CleanUpStack;
+		} while	(CWsTop::NeedsHeapCheckAndRestart(startCount));
+
+	__UHEAP_MARKEND;
+
+	return(err);
+	}
+
+