Rework addition of Symbian splash screen to reduce the source impact (uses SVG from Bug 2414)
Notes: by using the OPTION SOURCEDIR parameter in the mifconv extension instructions, I can
arrange to use the same source file name in sfimage, without having to export over the original
Nokia file. This means that the name inside splashscreen.mbg is the same, which removes the need
for the conditional compilation in SplashScreen.cpp, and gets rid of sf_splashscreen.mmp.
/*
* 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");
}