startupservices/SplashScreen/src/SplashScreen.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 14:43:04 +0300
branchRCL_3
changeset 82 4610cd70c542
parent 70 739cef680932
child 83 20e07ff6040b
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* Copyright (c) 2002-2008 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:  Displays single startup screen. Animation not supported.
*
*/


// SYSTEM INCLUDES
#include <w32std.h>
#include <coedef.h>
#include <data_caging_path_literals.hrh>
#include <splashscreen.mbg>
#include <AknIconSrvClient.h>
#include <startupdomainpskeys.h>

// USER INCLUDES
#include "SplashScreen.h"
#include "SplashScreenDefines.h"


// ==================== LOCAL FUNCTIONS ====================
LOCAL_C void DoItL();

GLDEF_C TInt E32Main()
	{
    TRACES("E32Main(): Start");

	__UHEAP_MARK;
	CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack

	TRAPD(error,DoItL()); // more initialization, then do Splash
	__ASSERT_ALWAYS(!error,User::Panic(KPanicMsg,error));
	delete cleanup; // destroy clean-up stack
	__UHEAP_MARKEND; // check no memory leak
    TRACES("E32Main(): End");
	return KErrNone;
	}

// 120 seconds (the splash should have been killed
// by the Starter before this runs out)
const TInt KSplashTimeout=(2* 60 * 1000000);


///////////////////////////////////////////////////////////////////////////////
////////////////////////// CWindow implementation /////////////////////////////
///////////////////////////////////////////////////////////////////////////////

CWindow::CWindow(CWsClient* aClient)
: iClient(aClient)
	{
    TRACES("CWindow::CWindow()");
	}

void CWindow::ConstructL (const TRect& aRect, CWindow* aParent)
	{
    TRACES("CWindow::ConstructL(): Start");

	// If a parent window was specified, use it; if not, use the window group
	// (aParent defaults to 0).
	RWindowTreeNode* parent= aParent ? (RWindowTreeNode*) &(aParent->Window()) : &(iClient->iGroup);
	iWindow=RWindow(iClient->iWs); // use app's session to window server
	User::LeaveIfError(iWindow.Construct(*parent,(TUint32)this));
    TRACES1("CWindow::ConstructL(): Start - window handle is: 0x%08x", this);
	iRect = aRect;
	iWindow.SetExtent(iRect.iTl, iRect.Size()); // set extent relative to group coords
	iWindow.Activate(); // window is now active
    TRACES("CWindow::ConstructL(): End");
	}


CWindow::~CWindow()
	{
    TRACES("CWindow::~CWindow(): Start");
	iWindow.Close(); // close our window
    TRACES("CWindow::~CWindow(): End");
	}

RWindow& CWindow::Window()
	{
    TRACES("CWindow::Window()");
	return iWindow;
	}

CWindowGc* CWindow::SystemGc()
	{
    TRACES("CWindow::SystemGc()");
	return iClient->iGc;
	}


///////////////////////////////////////////////////////////////////////////////
////////////////////////// CWsRedrawer implementation /////////////////////////
///////////////////////////////////////////////////////////////////////////////

CWsRedrawer::CWsRedrawer()
: CActive(CActive::EPriorityLow)
	{
    TRACES("CWsRedrawer::CWsRedrawer()");
	}

void CWsRedrawer::ConstructL(CWsClient* aClient)
	{
    TRACES("CWsRedrawer::ConstructL(): Start");
	iClient=aClient; // remember WsClient that owns us
	CActiveScheduler::Add(this); // add ourselves to the scheduler
	IssueRequest(); // issue request to draw
    TRACES("CWsRedrawer::ConstructL(): End");
	}

CWsRedrawer::~CWsRedrawer()
	{
    TRACES("CWsRedrawer::~CWsRedrawer(): Start");
	Cancel();
    TRACES("CWsRedrawer::~CWsRedrawer(): End");
	}

void CWsRedrawer::IssueRequest()
	{
    TRACES("CWsRedrawer::IssueRequest(): Start");
	iClient->iWs.RedrawReady(&iStatus);
	SetActive();
    TRACES("CWsRedrawer::IssueRequest(): End");
	}

void CWsRedrawer::DoCancel()
	{
    TRACES("CWsRedrawer::DoCancel(): Start");
	iClient->iWs.RedrawReadyCancel();
    TRACES("CWsRedrawer::DoCancel(): End");
	}

void CWsRedrawer::RunL()
	{
    TRACES("CWsRedrawer::RunL(): Start");

	// find out what must be done
	TWsRedrawEvent redrawEvent;
    iClient->iWs.GetRedraw(redrawEvent); // get event
	CWindow* window=(CWindow*)(redrawEvent.Handle()); // get window
	if (window)
		{
        TRACES1("CWsRedrawer::RunL(): window - 0x%08x", window);
		TRect rect=redrawEvent.Rect(); // and rectangle that needs redrawing
		// now do drawing
		iClient->iGc->Activate(window->Window());
		window->Window().BeginRedraw(rect);
		window->Draw(rect);
		window->Window().EndRedraw();
		iClient->iGc->Deactivate();
		}
	// maintain outstanding request
	IssueRequest();
    TRACES("CWsRedrawer::RunL(): End");
	}

CTimeout::CTimeout()
:   CTimer(0)
	{
    TRACES("CTimeout::CTimeout()");
	CActiveScheduler::Add(this);
	}

void CTimeout::ConstructL(CMainWindow* aWindow)
	{
    TRACES("CTimeout::ConstructL(): Start");
    CTimer::ConstructL();
	SetMainWindow( aWindow );
    TRACES("CTimeout::ConstructL(): End");
	}

void CTimeout::SetMainWindow( CMainWindow* aWindow )
    {
	iWindow = aWindow;
    }

void CTimeout::RunL()
	{
    TRACES("CTimeout::RunL(): Start");
	CActiveScheduler::Stop();
    if  ( iWindow )
        {
    	iWindow ->Client()->Group().SetOrdinalPosition(0,ECoeWinPriorityNeverAtFront);	// Background - so it's no more visible
        }
    TRACES("CTimeout::RunL(): End");
	}


/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// CWsClient implementation ////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
CWsClient::CWsClient()
: CActive(CActive::EPriorityStandard),
  iPSRemoveSplashState( ESplashRunning )
	{
    TRACES("CWsClient::CWsClient()");
	}

void CWsClient::ConstructL()
	{
    TRACES("CWsClient::ConstructL(): Start");

    RProperty::Define(KPSUidStartup,
                      KPSSplashShutdown,
                      RProperty::EInt,
                      KReadPolicy,
                      KWritePolicy );
    RProperty::Set( KPSUidStartup, KPSSplashShutdown, iPSRemoveSplashState );
	CActiveScheduler::Install(new (ELeave) CActiveScheduler);
	CActiveScheduler::Add(this);
    iProperty.Attach( KPSUidStartup, KPSSplashShutdown );
    iProperty.Subscribe( iStatus );

	// get a session going
	User::LeaveIfError(iWs.Connect());

	// construct screen device and graphics context
	iScreen=new (ELeave) CWsScreenDevice(iWs); // make device for this session
	User::LeaveIfError(iScreen->Construct( 0 )); // and complete its construction
	User::LeaveIfError(iScreen->CreateContext(iGc)); // create graphics context
    iLastScreenMode = iScreen->CurrentScreenMode();
    TRACES1("CWsClient::ConstructL() - iLastScreenMode: %d", iLastScreenMode);

	// construct our one and only window group
	iGroup=RWindowGroup(iWs);
	User::LeaveIfError(iGroup.Construct( (TInt) this,ETrue)); // meaningless handle; enable focus
    // Set our name for sending commands via key-events
    iGroup.SetName(KSplashScreenWindowGroup);

    TInt error = iGroup.EnableScreenChangeEvents();
    TRACES1("CWsClient::ConstructL() - enable screen change events: %d", error);

	// construct redrawer
	iRedrawer=new (ELeave) CWsRedrawer;
	iRedrawer->ConstructL(this);
    User::LeaveIfError( RAknIconSrvClient::Connect() );
	// construct main window
	ConstructMainWindowL();

    iWs.EventReady(&iStatus); // request an event
	SetActive(); // so we're now active
	// request first event and start scheduler

    TRACES("CWsClient::ConstructL(): About to start CActiveScheduler");

	CActiveScheduler::Start(); // start the active scheduler

    TRACES("CWsClient::CWsClient(): End");
	}

CWsClient::~CWsClient()
	{
    TRACES("CWsClient::~CWsClient(): Start");
    RAknIconSrvClient::Disconnect();
	// neutralize us as an active object
	Deque(); // cancels and removes from scheduler
	// get rid of scheduler and all attached objects
	delete CActiveScheduler::Current(); // delete the scheduler
	// get rid of everything we allocated
	delete iGc;
	delete iScreen;
	delete iRedrawer;
	// destroy window group
	iGroup.Close();
	// finish with window server
    Cancel();
    iProperty.Close();
	iWs.Close();
    TRACES("CWsClient::~CWsClient(): End");
	}

void CWsClient::Exit()
	{
    TRACES("CWsClient::Exit(): Start");
	CActiveScheduler::Stop();
    TRACES("CWsClient::Exit(): End");
	}

void CWsClient::IssueRequest()
	{
    TRACES("CWsClient::IssueRequest(): Start");
	iWs.EventReady(&iStatus); // request an event
	SetActive(); // so we're now active
    TRACES("CWsClient::IssueRequest(): End");
	}

void CWsClient::DoCancel()
	{
    TRACES("CWsClient::DoCancel(): Start");
	iWs.EventReadyCancel(); // cancel event request
    TRACES("CWsClient::DoCancel(): End");
	}

void CWsClient::ConstructMainWindowL()
	{
    TRACES("CWsClient::ConstructMainWindowL()");
	}



//////////////////////////////////////////////////////////////////////////////
//				Implementation for derived window classes
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//					 CMainWindow implementation							//
//////////////////////////////////////////////////////////////////////////////

/****************************************************************************\
|	Function:	Constructor/Destructor for CMainWindow
|				Doesn't do much, as most initialisation is done by the
|				CWindow base class.
|	Input:		aClient		Client application that owns the window
\****************************************************************************/
CMainWindow::CMainWindow (CWsClient* aClient)
: CWindow (aClient)
	{
    TRACES("CMainWindow::CMainWindow()");
	}


CMainWindow::~CMainWindow ()
	{
    TRACES("CMainWindow::~CMainWindow(): Start");
    delete iBitmap;
    TRACES("CMainWindow::~CMainWindow(): End");
	}

void CMainWindow::ConstructL (const TRect& aRect, CWindow* aParent)
	{
    TRACES("CMainWindow::ConstructL(): Start");

    TInt err( KErrNone );

	CWindow::ConstructL(aRect, aParent);

    TParse* fp = new(ELeave) TParse();
    fp->Set(KSplashBitmapName, &KDC_APP_BITMAP_DIR, NULL);
    TRACES1("CMainWindow::ConstructL(): Load Bitmap from %S", &fp->FullName());

    RFs fs;
    TInt thisTry = 0;
    while ( ( err = fs.Connect() ) != KErrNone && ( thisTry++ ) <= KTriesToConnectServer )
        {
        User::After( KTimeBeforeRetryingServerConnection );
        }

    TFindFile findFile( fs );
    err = findFile.FindByPath( fp->FullName(), NULL );
    fs.Close();
    if ( !err )
        {
        TRACES("CMainWindow::ConstructL(): Image found");
        iBitmap = AknIconUtils::CreateIconL( fp->FullName(), EMbmSplashscreenQgn_startup_screen );
        AknIconUtils::ExcludeFromCache(iBitmap);
        AknIconUtils::SetSize( iBitmap, iRect.Size(), EAspectRatioPreservedAndUnusedSpaceRemoved );
        }
    else
        {
        TRACES("CMainWindow::ConstructL(): Image not found");
        }

    delete fp;

    TRACES("CMainWindow::ConstructL(): End");
	}


/****************************************************************************\
|	Function:	CMainWindow::Draw
|	Purpose:	Redraws the contents of CMainWindow within a given
|				rectangle. As CMainWindow has no contents, it simply
|				clears the redraw area. A blank window could be used here
|				instead. The Clear() is needed because a redraw should
|				always draw to every pixel in the redraw rectangle.
|	Input:		aRect	Rectangle that needs redrawing
|	Output:		None
\****************************************************************************/
void CMainWindow::Draw(const TRect& aRect)
	{
    TRACES("CMainWindow::Draw(): Start");

	CWindowGc* gc=SystemGc(); // get a gc
	gc->SetClippingRect(aRect); // clip outside this rect
    TRACES2("CMainWindow::Draw(): Rect: X0=%d Y0=%d", aRect.iTl.iX, aRect.iTl.iY);
    TRACES2("CMainWindow::Draw(): Rect: X1=%d Y1=%d", aRect.iBr.iX, aRect.iBr.iY);

    TRACES1("CMainWindow::Draw(): iBitmap = %d", iBitmap);
	if (iBitmap)
		{
        TSize bmpSizeInPixels = iBitmap->SizeInPixels();
        //center image to the center of the screen
        TInt xDelta = ( aRect.Width() - bmpSizeInPixels.iWidth ) / 2;
        TInt yDelta = ( aRect.Height() - bmpSizeInPixels.iHeight ) / 2;
        TPoint pos = TPoint( xDelta , yDelta ); // displacement vector
        TRACES2("CMainWindow::Draw(): Image top left corner: X=%d Y=%d", pos.iX, pos.iY);
        gc->Clear();
		gc->BitBlt(pos, iBitmap);
		}
	else
		{
        TRACES("CMainWindow::Draw(): Image not available. Draw lines from corner to corner");
		TRect rect(Window().Position(), Window().Size());
		gc->DrawLine(rect.iTl, rect.iBr);
		gc->DrawLine(TPoint(rect.iTl.iX, rect.iBr.iY), TPoint(rect.iBr.iX, rect.iTl.iY));
		}
    TRACES("CMainWindow::Draw(): End");
	}

/****************************************************************************\
|	Function:	CMainWindow::HandlePointerEvent
|	Purpose:	Handles pointer events for CMainWindow.  Doesn't do
|				anything except get the co-ordinates where the pointer
|				event occurred.
|	Input:		aPointerEvent	The pointer event
|	Output:		None
\****************************************************************************/
void CMainWindow::HandlePointerEvent (TPointerEvent& /*aPointerEvent*/)
    {
    TRACES("CMainWindow::HandlePointerEvent(): Start");
//	TPoint point = aPointerEvent.iPosition;
//	(void)point;
    TRACES("CMainWindow::HandlePointerEvent(): End");
	}

//////////////////////////////////////////////////////////////////////////////
//					 CSplashWsClient implementation						//
//////////////////////////////////////////////////////////////////////////////

/****************************************************************************\
|	Function:	Constructor/Destructor for CSplashWsClient
|				Destructor deletes everything that was allocated by
|				ConstructMainWindowL()
\****************************************************************************/
CSplashWsClient::CSplashWsClient()
	{
    TRACES("CSplashWsClient::CSplashWsClient()");
	}

CSplashWsClient::~CSplashWsClient ()
	{
    TRACES("CSplashWsClient::~CSplashWsClient(): Start");
    if  ( iMainWindow )
        {
        TRACES("CSplashWsClient::~CSplashWsClient(): To background");
    	iMainWindow->Client()->Group().SetOrdinalPosition(-1,ECoeWinPriorityNormal);	// Back to the normal position
        iWs.Flush();
        }
	delete iMainWindow;
	delete iTimeout;
    TRACES("CSplashWsClient::~CSplashWsClient(): End");
	}

/****************************************************************************\
|	Function:	CSplashWsClient::ConstructMainWindowL()
|				Called by base class's ConstructL
|	Purpose:	Allocates and creates all the windows owned by this client
|				(See list of windows in CSplashWsCLient declaration).
\****************************************************************************/

void CSplashWsClient::ConstructMainWindowL()
	{
    TRACES("CSplashWsClient::ConstructMainWindowL(): Start");

	TSize windowSize=iScreen->SizeInPixels();

    CMainWindow* window = new (ELeave) CMainWindow(this);
    CleanupStack::PushL( window );
	window->ConstructL(TRect(TPoint(0,0), windowSize));
	window->Client()->Group().SetOrdinalPosition(0,ECoeWinPriorityAlwaysAtFront + 1);	// in front of the Status Bar
    delete iMainWindow;
    iMainWindow = window;
    CleanupStack::Pop( window );

    if  ( iTimeout == NULL )
        {
	    iTimeout = new (ELeave) CTimeout;
	    iTimeout->ConstructL(iMainWindow);
	    iTimeout->After(KSplashTimeout);
        }
    else
        {
        iTimeout->SetMainWindow( window );
        }

    TRACES("CSplashWsClient::ConstructMainWindowL(): End");
	}


/****************************************************************************\
|	Function:	CSplashWsClient::RunL()
|				Called by active scheduler when an even occurs
|	Purpose:	Processes events according to their type
|				For key events: calls HandleKeyEventL() (global to client)
|				For pointer event: calls HandlePointerEvent() for window
|                                  event occurred in.
\****************************************************************************/
void CSplashWsClient::RunL()
	{
    TRACES("CSplashWsClient::RunL(): Start");

    TInt state;
    RProperty::Get( KPSUidStartup, KPSSplashShutdown, state );
    TRACES1("CSplashWsClient::RunL(): KPSSplashShutdown state = %d", state);

    if ( state != iPSRemoveSplashState )
        {
        TRACES("CSplashWsClient::RunL(): KPSSplashShutdown state has changed -> PS event");
        if ( state == ESplashShutdown )
            {
            TRACES("CSplashWsClient::RunL(): Exit requested");
            Exit();
            }
        }
    else
        {
        TRACES("CSplashWsClient::RunL(): WS event");

        // get the event
	    iWs.GetEvent(iWsEvent);
	    const TInt eventType = iWsEvent.Type();

        // take action on it
	    switch (eventType)
		    {
    		// window-group related event types
    		case EEventKey:
	    		{
                TRACES("CSplashWsClient::RunL(): EEventKey");
			    TKeyEvent& keyEvent=*iWsEvent.Key(); // get key event
    			HandleKeyEventL (keyEvent);
	            break;
    			}
            // window related events
    		case EEventPointer:
	    		{
                TRACES("CSplashWsClient::RunL(): EEventPointer");
			    CWindow* window=(CWindow*)(iWsEvent.Handle()); // get window
			    TPointerEvent& pointerEvent=*iWsEvent.Pointer();
			    window->HandlePointerEvent (pointerEvent);
    			break;
	    		}
            case EEventScreenDeviceChanged:
                {
                const TInt currentScreenMode = iScreen->CurrentScreenMode();
                TRACES2("CSplashWsClient::RunL() - EEventScreenDeviceChanged - iLastScreenMode: %d, currentScreenMode: %d", iLastScreenMode, currentScreenMode);
                if  ( iLastScreenMode != currentScreenMode )
                    {
                    RDebug::Printf("[SS] CSplashWsClient::RunL() - EEventScreenDeviceChanged - real screen mode change detected!!!!");
                    iScreen->SetAppScreenMode( currentScreenMode );
                    TPixelsTwipsAndRotation currentRot;
                    iScreen->GetScreenModeSizeAndRotation( currentScreenMode, currentRot );
                    iMainWindow->Window().SetExtent( TPoint(0, 0), currentRot.iPixelSize );
	                iMainWindow->Client()->Group().SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront + 10000);	// in front of the Status Bar
                    iMainWindow->Window().Invalidate();

                    iLastScreenMode = currentScreenMode;
                    }
                TRACES("CSplashWsClient::RunL() - EEventScreenDeviceChanged - done");
                }
                break;
		    default:
                TRACES("CSplashWsClient::RunL(): default");
    			break;
	        }
        IssueRequest(); // maintain outstanding request
        }
    TRACES("CSplashWsClient::RunL(): End");
	}


/****************************************************************************\
|	Function:	CSplashWsClient::HandleKeyEventL()
|
|	Purpose:	Processes key events for CSplashWsClient
|				Gets the key code from the key event.  Exits on 'Escape'
\****************************************************************************/
void CSplashWsClient::HandleKeyEventL (TKeyEvent& /*aKeyEvent*/)
    {
    TRACES("CSplashWsClient::HandleKeyEventL(): Start");
    TRACES("CSplashWsClient::HandleKeyEventL(): End");
	}

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//					 Main program starts here								//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

LOCAL_C void DoItL()
	{
	// make new client
    TRACES("DoItL(): Start");

	CSplashWsClient* client=new (ELeave) CSplashWsClient; // allocate new client
	CleanupStack::PushL(client); // push, just in case
	client->ConstructL(); // construct and run
	CleanupStack::PopAndDestroy(); // destruct

    TRACES("DoItL(): End");
	}