Screen Saver API: Using Screen Saver API

Using Screen Saver API means implementing a plug-in, which uses services of the host.

Implementing custom plug-in

Plug-ins derive from CScreensaverPluginInterfaceDefinition.

class CExampleScreenSaverPlugin:
    public CScreensaverPluginInterfaceDefinition
    {    

    public: 

        static CExampleScreenSaverPlugin* NewL();
        virtual ~CExampleScreenSaverPlugin();     

    public: // from CScreensaverPluginInterfaceDefinition        

        virtual TInt InitializeL( MScreensaverPluginHost *aHost );
        virtual TInt Draw( CWindowGc& aGc );
        virtual const TDesC16& Name() const;
        virtual TInt Capabilities();
        virtual TInt PluginFunction(
            TScPluginCaps aFunction,
            TAny* aParam );
        virtual TInt HandleScreensaverEventL(
            TScreensaverEvent aEvent,
            TAny* aData );                           

    private: // data

        MScreensaverPluginHost* iHost; // Host, not owned.
        TRect iRect; // Rect of display area.

    };

MMP file fragment.

TARGET          ExampleScreenSaverPlugin.dll
TARGETTYPE      PLUGIN 
UID             0x10009D8D 0xE000ABCD
CAPABILITY      NetworkServices LocalServices Location ReadUserData WriteUserData
ReadDeviceData WriteDeviceData SwEvent UserEnvironment PowerMgmt

START RESOURCE ..\data\10207447.rss 
TARGET          ExampleScreenSaverPlugin.rsc
END

SOURCE          ExampleScreenSaverPlugin.cpp

SYSTEMINCLUDE   \epoc32\include
SYSTEMINCLUDE   \epoc32\include\ecom

LIBRARY         ecom.lib 
LIBRARY         euser.lib

ECom registration resource file fragment.

The opaque_data contains the plug-in capabilities in string format. Same capability values must be returned in numeric format by MScreensaverPlugin::Capabilities().

MScreensaverPlugin::Name() or display_name provide the string displayed to the user in Screensaver settings view in the Themes application. display_name is not used unless MScreensaverPlugin::Name() returns an empty string. This way the plug-in registration file need not contain localizable information.

Note that in S60 release 3.0, display_name was used instead of MScreensaverPlugin::Name().

#include <RegistryInfo.rh>
#include "ScreensaverPluginIntDef.hrh"

RESOURCE REGISTRY_INFO theInfo
    {
    dll_uid = 0xE000ABCD;
    interfaces =
        {
        INTERFACE_INFO
            {
            interface_uid = KCScreensaverPluginInterfaceDefinitionUid;
            implementations =
                {
                IMPLEMENTATION_INFO
                    {
                    implementation_uid = 0xE0001234;
                    version_no = 1;
                    display_name = "Example plugin";
                    default_data = "";
                    opaque_data = "07";
                    }
                };
            }
        };
    }

The ECom plug-in must export its implementation proxy table:

#include    <e32Std.h>
#include    <ImplementationProxy.h>

const TImplementationProxy ImplementationTable[] =
    {
    IMPLEMENTATION_PROXY_ENTRY( 0xE0001234, CExampleScreenSaverPlugin::NewL )
    };

EXPORT_C const TImplementationProxy*
    ImplementationGroupProxy( TInt& aTableCount )
    {
    aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
    return ImplementationTable;
    }

Instance creation through ECom should be light. It is possible that plug-ins are created but never initialized and drawn. For example, if the plug-in supports the configure function, the Themes application creates an instance and calls plug-in function EScpCapsConfigure, without initializing the plug-in.

The Screensaver application will call InitializeL() to prepare the plug-in for drawing. Initialization for drawing-related resources should be implemented in InitializeL() instead of ConstructL().

void CExampleScreenSaverPlugin::ConstructL()
    {
    }

TInt CExampleScreenSaverPlugin::InitializeL
( MScreensaverPluginHost *aHost )
    {     
    iScreenSaverHost = aHost;
    // Prepare for drawing: load resources, etc.
    // ...
    return KErrNone;
    }

Capabilities must match the supported plug-in functions. Capabilities are read by, and the plug-in functions are called from the Themes application.

TInt CExampleScreenSaverPlugin::Capabilities()
    {
    return EScpCapsConfigure |
           EScpCapsSelectionNotification |
           EScpCapsPreviewNotification;
    }

TInt CExampleScreenSaverPlugin::PluginFunction(
            TScPluginCaps aFunction,
            TAny* /*aParam*/)
    { 
    switch ( aFunction )
        {
        case EScpCapsConfigure:
            {
            // Called from Themes.
            // Options->Settings selected.
            // Launch dialog to configure plug-in settings.
            // InitializeL() may not have been called.
            // ...
            break;
            }
        case EScpCapsSelectionNotification:
            {
            // Called from Themes.
            // Options->Apply selected.
            // ...
            break;
            }
        case EScpCapsPreviewNotification:
            {
            // Called from Themes.
            // Options->Preview selected.
            // Prepare for preview.
            // ...
            break;
            }
        }
    return KErrNone;                                                
    }

The plug-in responds to screensaver events, sent by the host.

TInt CExampleScreenSaverPlugin::HandleScreensaverEventL(
        TScreensaverEvent aEvent,
        TAny* /*aData*/ )
    {
    switch ( aEvent )
        {
        case EScreensaverEventNothing:
            {
            // This event should never be delivered.
            break;
            }

        case EScreensaverEventStarting:
            {
            // This event is delivered when screensaver is about to start.
            break;
            }

        case EScreensaverEventStopping:
            {
            // This event is delivered when screensaver is stopped.
            // In case plug-in has internal timers while screensaver
            // is displayed, here you can stop those.
            break;
            }

        case EScreensaverEventDisplayChanged:
            {
            // This event needs to be handled when display resolution
            // or orientation is changed.
            // You can refresh information about display using
            // MScreensaverPluginHost::DisplayInfo method.
            break;
            }

        case EScreensaverEventTimeout:
            {
            // This event is delivered when plug-in requested
            // timeout expires. 
            // See MScreensaverPluginHost::RequestTimeout.
            break;
            }

        case EScreensaverEventPreview:
            {
            // This event is delivered by screensaver application
            // when plug-in started to be used in preview mode.
            // Note that themes application
            // informs of preview  activation through PluginFunction.
            break;
            }

        default:
            {
            // Ignore any new events.
            }
            break;
        }

    return KErrNone;
    }

Plug-ins implement the drawing code in the Draw() method. Based on the refresh timer, the host calls Draw() periodically. Draw() receives the window context to be used for drawing as parameter

Overriding standard indicators

By default, Screensaver draws the indicators and the plug-in only draws the custom graphical object. It is possible to turn standard indicators off.

iHost->OverrideStandardIndicators();

Typical uses of this feature include:

Getting indicator data

The following code snippet gets the number of missed calls from the host. This is typically used if the plug-in draws custom indicators.

TInt missedCalls = 0;
TIndicatorPayload payload;
TInt err = iHost->GetIndicatorPayload
    ( EScreensaverIndicatorIndexNewMissedCalls, payload );
if ( KErrNone == err )
    {
    missedCalls = payload.iInteger;
    }

Setting refresh timer

Plug-ins can adjust the refresh timer. See Power saving considerations.

iHost->SetRefreshTimerValue( 10000000 ); // 10 seconds

Disabling refresh

If refresh timer is disabled, the host does not call the Draw() method of the plug-in.

iHost->UseRefreshTimer( EFalse );

Querying display info

The following example demonstrates screensaver event handling. In response to the EScreensaverEventDisplayChanged event, a display info is queried from the host.

Note that TScreensaverDisplayInfo::iSize must be set by the caller.

In this example, the plug-in copies the display TRect to a member variable.

TInt CExampleScreenSaverPlugin::HandleScreensaverEventL(
            TScreensaverEvent aEvent,
            TAny* /*aData*/ )
    {
    if ( EScreensaverEventDisplayChanged == aEvent )
        {
        // Display Changed is called when there is a change in the size
        // of the window and when the parent control is set for the 
        // first time.        
        TScreensaverDisplayInfo displayInfo;
        displayInfo.iSize = sizeof( TScreensaverDisplayInfo );
        User::LeaveIfError( iHost->DisplayInfo( &displayInfo ) );
        iRect = displayInfo->iRect; // Save display rect.
        }
    //...
    return KErrNone;
    }

Configuring the plug-in

Configurable plug-ins must advertise capability EScpCapsConfigure. Plug-in function EScpCapsConfigure can be used to display the configuration UI to the user.

Note that plug-in function EScpCapsConfigure may be called without InitializeL() being called first.

Management and persistence of the plug-in specific settings are beyond the scope of this document. One possible implementation is using Central Repository.

Suspending drawing

Plug-ins can suspend drawing for a requested period of time, or indefinitely. During this standard screensaver view is drawn.

iHost->Suspend( -1 ); // Value in microsecods.
                      // Negative value: suspend indefinitely.

Entering partial display mode

The following code snippet demonstrates using the partial display mode.

TInt CExampleScreenSaverPlugin::Draw( CWindowGc& aGc )
    {
    TRect rect = TRect( 0, 0, 240, 40 );
    aGc.Clear( rect );
    aGc.SetPenColor( KRgbBlack );
    aGc.SetBrushStyle( CGraphicsContext::ESolidBrush );
    aGc.SetPenStyle( CGraphicsContext::ESolidPen );
    aGc.UseFont( iEikonEnv->TitleFont() );
    aGc.DrawText( _L("hello world"), TPoint( 0, 30 ) );
    TScreensaverPartialMode partialMode;
    partialMode.iBpp = 0; 
    partialMode.iType = EPartialModeTypeMostPowerSaving;
    // Call SetActiveDisplayArea last - it may cause flush.
    (void)iHost->SetActiveDisplayArea( rect, partialMode );
    return KErrNone;
    }

Exiting partial display mode

The following code snippet cancels the effect of the SetActiveDisplayArea() method. The whole display area is activated.

iHost->ExitPartialMode ();

Error handling

Screen Saver API uses standard Symbian OS error reporting mechanism and standard error codes.

In certain error situations plug-ins may detect unrecoverable errors. The plug-in may choose to disable itself and revert back to the default screensaver, by calling MScreensaverPluginHost::RevertToDefaultSaver(). This causes the plug-in to be unloaded. An example for such a situation could be if the plug-in’s graphical object is digitally protected, and the client Rights Object to render the graphical object has expired.

It should be noted, however, that the plug-in host also has a fallback mechanism. If the plug-in fails to load, the host activates a default screensaver.

Memory overhead

Memory consumption of screensaver depends on the actual plug-in implementation.

Power saving considerations

Reducing power consumption is one of the primary considerations in Screensaver. When writing plug-ins, prefer low power consumption over fancy graphics. Screensaver runs when nobody is watching.

Limitations of the API

There is no function to query the maximum number of lines supported by the display hardware in partial display mode. As a rule of thumb, support for 50 lines could be assumed.


Copyright © Nokia Corporation 2001-2008
Back to top