Using Screen Saver API means implementing a plug-in, which uses services of the host.
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
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:
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; }
Plug-ins can adjust the refresh timer. See Power saving considerations.
iHost->SetRefreshTimerValue( 10000000 ); // 10 seconds
If refresh timer is disabled, the host does not call the Draw()
method
of the plug-in.
iHost->UseRefreshTimer( EFalse );
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; }
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.
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.
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; }
The following code snippet cancels the effect of the SetActiveDisplayArea()
method.
The whole display area is activated.
iHost->ExitPartialMode ();
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 consumption of screensaver depends on the actual plug-in implementation.
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.
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.