Symbian
Symbian Developer Library

SYMBIAN OS V9.4

Feedback

[Index] [Previous] [Next]


Direct: Direct Screen Access

[Top]


Example code

Found in: Examples\Graphics\Ws\Direct\

Note: This example is designed to work properly only with techview, there is no guarantee that it will work properly with other interfaces.

[Top]


Description

Direct demonstrates the window server's direct screen area (CDirectScreenAccess) interface.

The example has an engine, CLifeEngine, for the famous "Game of Life" algorithm, which generates grids of cells, each update being derived by simple rules from the previous generation. The initial configuration of the cells is random.

The UI simply has little user interaction. It simply draws the current grid using CDirectScreenAccess, and requests the engine to generate the next update. The UI classes are:

[Top]


Usage

Commands are given to the example through its Life menu. The commands are:

[Top]


Files

These are the main files contained in the examples:

Some extra files may be needed to run the examples, and these will be found in the appropriate examples directory.


Direct.mmp

// Direct.mmp
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

TARGET          Direct.exe        //  Only exe type is compatible with v9.1
TARGETTYPE      exe
UID         0x100039CE 0xE8000054
VENDORID       0x70000001

SOURCEPATH      .
SOURCE          Direct.cpp CDirectDisplayLife.cpp CLifeEngine.cpp 
USERINCLUDE     .
SYSTEMINCLUDE   \epoc32\include
SYSTEMINCLUDE   \epoc32\include\techview


START RESOURCE Direct.rss         // Rss file necessary in v9.1
TARGET          Direct.rsc
TARGETPATH      \Resource\Apps
HEADER
LANG 01       // Build English language versions
END


// Application exe registration resource file
start resource    Direct_reg.rss           //   reg file necessary in v9.1
targetpath         \private\10003a3f\apps
//lang          01
end

start resource Direct_loc.rss         // loc file necessary in v9.1
//targetpath    \resource\apps
lang           01
end

LIBRARY         euser.lib
LIBRARY         apparc.lib
LIBRARY         cone.lib
LIBRARY         eikcore.lib 
LIBRARY         ws32.lib    
LIBRARY         bitgdi.lib

Direct_reg.rss

// Direct.RSS
//
// Copyright (c) 2005 Symbian Software Ltd.  All rights reserved.
//

#include <appinfo.rh>

UID2 KUidAppRegistrationResourceFile
UID3 0xE8000054
RESOURCE APP_REGISTRATION_INFO
 { 
 app_file = Direct;
 localisable_resource_file="\\resource\\apps\\Direct_loc.rss";
 hidden=KAppNotHidden;
 embeddability=KAppNotEmbeddable;
 newfile=KAppDoesNotSupportNewFile;
 launch=KAppLaunchInForeground;
 }

Direct.rss

// Direct.rss
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

NAME HELO

#include <eikon.rh>
#include <eikon.rsg>

#include "Direct.hrh"

RESOURCE RSS_SIGNATURE { }

RESOURCE TBUF { buf=""; }

RESOURCE EIK_APP_INFO
    {
    menubar=r_example_menubar;
    hotkeys=r_example_hotkeys;
    }

RESOURCE HOTKEYS r_example_hotkeys
    {
    control=
        {
        HOTKEY { command=EEikCmdExit; key='e'; },
        HOTKEY { command=EExampleCmd1; key='s'; },
        HOTKEY { command=EExampleCmd2; key='t'; }
        };
    }

RESOURCE MENU_BAR r_example_menubar
    {
    titles=
        {
        MENU_TITLE { menu_pane=r_example_file_menu; txt="Life"; }
        };
    }

RESOURCE MENU_PANE r_example_file_menu
    {
    items=
        {
        MENU_ITEM { command=EExampleCmd1; txt="Start"; },
        MENU_ITEM { command=EExampleCmd2; txt="Test overlay"; },
        MENU_ITEM { command=EEikCmdExit; txt="Close"; }
        };
    }

Direct_loc.rss

#include <appinfo.rh>
   
RESOURCE LOCALISABLE_APP_INFO
{
short_caption = "Direct";
caption_and_icon =
    {
    CAPTION_AND_ICON_INFO
        {
        caption = "Direct";
        number_of_icons = 0; // each icon must be a bitmap/mask pair
        }
    };
}     

Direct.hrh

// Direct.hrh
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

#define EExampleCmd1 0x1001
#define EExampleCmd2 0x1002

Direct.h

// Direct.h
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

// Application framework classes for Direct Screen Area (DSA) API example

#ifndef __DIRECT_H
#define __DIRECT_H

#include <coecntrl.h>
#include <coeccntx.h>
#include <coemain.h>

#include <eikappui.h>
#include <eikapp.h>
#include <eikdoc.h>
#include <uikon.hrh>

#include <Direct.rsg>
#include "Direct.hrh"

const TUid KUidExample = { 0xE8000054 };

class CDirectDisplayLife;
class CLifeEngine;

// View, a window containing a DSA
class CExampleAppView : public CCoeControl
    {
public:
    // View state
    enum {
        EDirectNotStarted=0,    // DSA not used
        EDirectStarted,         // DSA in use
        EDirectPaused           // Use of DSA temporarily halted
        };

public:
    // Construction & destruction
    CExampleAppView(CLifeEngine& aLifeEngine);
    ~CExampleAppView();
    void ConstructL(const TRect& aRect);

    // Start using the DSA
    void StartDirectL();
    // Pause use of the DSA
    void PauseDirect();
    // Restart use of the DSA after pausing
    void RestartDirect();

    // Gets the view state
    TInt State() const;

private:
    // from CCoeControl
    void Draw(const TRect&) const;

private:
    // The object that handles the DSA
    CDirectDisplayLife* iDirectDisplayLife;
    // The data the view displays
    CLifeEngine& iLifeEngine;
    // View state
    TInt iState;
    };

// App UI, handles user commands
class CExampleAppUi : public CEikAppUi
    {
public:
    // Construction & destruction
    void ConstructL();
    ~CExampleAppUi();

private:
    // from CEikAppUi
    void HandleCommandL(TInt aCommand);

private:
    class COverlayDialog: public CActive
        {
    public:
        COverlayDialog();
        ~COverlayDialog();
        void ShowDialog();

    private:
        void RunL();
        void DoCancel();

    private:
        RNotifier iNotifier;
        TInt iR;
        };

private:
    // The app view
    CExampleAppView* iAppView;
    COverlayDialog* iOverlayDialog;
    };

// App document. Owns the engine.
class CExampleDocument : public CEikDocument
    {
public:
    // Construction & destruction
    CExampleDocument(CEikApplication& aApp);
    ~CExampleDocument();

    // Gets the engine
    CLifeEngine& LifeEngine() const;

private:
    // from CEikDocument
    CEikAppUi* CreateAppUiL();

private:
    // The engine
    CLifeEngine* iLifeEngine;
    };

// Application class
class CExampleApplication : public CEikApplication
    {
private: // from CApaApplication
    CApaDocument* CreateDocumentL();
    TUid AppDllUid() const;
    };

#endif

Direct.cpp

// Direct.cpp
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

#include "CLifeEngine.h"
#include "Direct.h"
#include "CDirectDisplayLife.h"

#include <eikenv.h>
#include <eikmenub.h>

#include <eikspane.h>

#include <EikStart.h>

//
// CExampleAppView
//

CExampleAppView::CExampleAppView(CLifeEngine& aLifeEngine)
: iLifeEngine(aLifeEngine)
    {
    }

void CExampleAppView::ConstructL(const TRect& aRect)
    {
    // Create window
    CreateWindowL();
    SetRect(aRect);

    // Set up direct displayer for life engine
    iDirectDisplayLife = new (ELeave) CDirectDisplayLife (
        iEikonEnv->WsSession(),      // Window server session
        Window(),                   // The window itself
        iLifeEngine);
    iDirectDisplayLife -> ConstructL();

    ActivateL();
    }

CExampleAppView::~CExampleAppView()
    {
    delete iDirectDisplayLife;
    }

// Start using the DSA
void CExampleAppView::StartDirectL()
    {
    iDirectDisplayLife -> StartL();
    iState = EDirectStarted;
    }

// Pause use of the DSA
void CExampleAppView::PauseDirect()
    {
    iState = EDirectPaused;   
    iDirectDisplayLife -> Cancel();
    }

// Restart use of the DSA after pausing
void CExampleAppView::RestartDirect()
    {
    iState = EDirectStarted;
    iDirectDisplayLife -> Restart(RDirectScreenAccess::ETerminateCancel);
    }

// Gets the view state
TInt CExampleAppView::State() const
    {
    return iState;
    }


void CExampleAppView::Draw(const TRect& /*aRect*/) const
    {
    CWindowGc& gc = SystemGc();
    // white out whole rectangle
    TRect rect=Rect();
    gc.SetPenStyle(CGraphicsContext::ENullPen);
    gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
    gc.SetBrushColor(KRgbWhite);
    gc.DrawRect(rect);
    // border
    rect.Shrink(10,10);
    gc.SetBrushStyle(CGraphicsContext::ENullBrush);
    gc.SetPenStyle(CGraphicsContext::ESolidPen);
    gc.DrawRect(rect);
    }


//
// CExampleAppUi
//

void CExampleAppUi::ConstructL()
    {
    BaseConstructL();

    // Construct the view
    iAppView=new(ELeave) CExampleAppView(static_cast<CExampleDocument*>(Document())->LifeEngine());
    iAppView->ConstructL(ClientRect());

    // Construct the example overlaying dialog
    iOverlayDialog = new (ELeave) COverlayDialog();
    CActiveScheduler::Add(iOverlayDialog);
    }

CExampleAppUi::~CExampleAppUi()
    {
    delete iAppView;
    iOverlayDialog->Cancel();
    delete iOverlayDialog;
    }

// Handle menu commands
void CExampleAppUi::HandleCommandL(TInt aCommand)
    {
    switch (aCommand)
        {
    // Start command
    case EExampleCmd1:
        // Different action required for very first start
        // And subsequent restarts
        if (iAppView -> State() == CExampleAppView::EDirectNotStarted)
            iAppView -> StartDirectL();
        else
            {
            iAppView -> PauseDirect();
            static_cast<CExampleDocument*>(Document())->LifeEngine().Reset();
            iAppView -> RestartDirect();
            }
        break;
    // Test overlay command
    case EExampleCmd2:
        iOverlayDialog->ShowDialog();
        break;
    // Close command
    case EEikCmdExit: 
        Exit();
        break;
        }
    }

//
// CExampleAppUi::COverlayDialog
//

CExampleAppUi::COverlayDialog::COverlayDialog()
:CActive(EPriorityStandard)
    {
    iNotifier.Connect();
    }

CExampleAppUi::COverlayDialog::~COverlayDialog()
    {
    Cancel();
    iNotifier.Close();
    }

void CExampleAppUi::COverlayDialog::ShowDialog()
    {
    _LIT(KLine1,"Overlaying dialog");
    _LIT(KLine2,"Owned by another thread");
    _LIT(KBut,"OK");

    // Use a notifier to display a dialog from the notifier server thread
    iNotifier.Notify(KLine1,KLine2,KBut,KBut,iR,iStatus);
    SetActive();
    }

void CExampleAppUi::COverlayDialog::RunL()
    {
    // Don't care what the dialog returned
    }

void CExampleAppUi::COverlayDialog::DoCancel()
    {
    }

//
// CExampleDocument
//

CExampleDocument::CExampleDocument(CEikApplication& aApp)
        : CEikDocument(aApp)
    {
    }

CExampleDocument::~CExampleDocument()
    {
    delete iLifeEngine;
    }

CLifeEngine& CExampleDocument::LifeEngine() const
    {
    return *iLifeEngine;
    }

CEikAppUi* CExampleDocument::CreateAppUiL()
    {
    // Get a random seed from the timer
    User::After(1);
    TTime now;
    now.HomeTime();

    // Create engine
    iLifeEngine = new (ELeave) CLifeEngine(now.Int64());
    return new(ELeave) CExampleAppUi;
    }

//
// CExampleApplication
//

TUid CExampleApplication::AppDllUid() const
    {
    return KUidExample;
    }

CApaDocument* CExampleApplication::CreateDocumentL()
    {
    return new (ELeave) CExampleDocument(*this);
    }

//
// DLL interface
//

EXPORT_C CApaApplication* NewApplication()
    {
    return new CExampleApplication;
    }


//  The below section is added to make the code compatible with v9.1
//  This is because only exe files are compatible with v9.1
#if (defined __WINS__ && !defined EKA2)        //  E32Dll used only when WINS defined and EKA2 not defined
GLDEF_C TInt E32Dll(enum TDllReason)     
    {
    return KErrNone;
    }
#else                                       //   else E32Main is used
GLDEF_C TInt E32Main()        
    {
    return EikStart::RunApplication(NewApplication);
    }
#endif

CDirectDisplayLife.h

// CDirectDisplayLife.h
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

#if !defined(__DIRECT_H__)
#define __DIRECT_H__

#include <w32std.h>

#include "CLifeEngine.h"

// Displays a running Game of Life using DSA API
class CDirectDisplayLife : 
    public CTimer,             
    public MDirectScreenAccess // Call backs from DSA
    {
public:
    // Construction & destruction
    CDirectDisplayLife (RWsSession& aClient, 
        RWindow& aWindow, 
        CLifeEngine& aLifeEngine);
    ~CDirectDisplayLife ();
    void ConstructL();

    // Start game display
    void StartL();
    
    // Implement MDirectScreenAccess
    void Restart(RDirectScreenAccess::TTerminationReasons aReason);
    void AbortNow(RDirectScreenAccess::TTerminationReasons aReason);

private:
    // Implement CTimer
    void RunL();
    void DoCancel();

private:
    // Window server handling
    RWsSession& iClient;
    RWindow& iWindow;

    // DSA objects
    CDirectScreenAccess* iDirectScreenAccess;
    CFbsBitGc* iGc;
    RRegion* iRegion;

    // Drawing constants
    static const TInt KBlockSize;
    static const TInt KGenerationInterval;
    static const TInt iXOrigin;
    static const TInt iYOrigin;

    // Life game engine
    CLifeEngine& iLifeEngine;
    };

#endif //__DIRECT_H__

CDirectDisplayLife.cpp

// CDirectDisplayLife.cpp
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

#include <coemain.h>

#include "CDirectDisplayLife.h"

// Dimension of each cell
const TInt CDirectDisplayLife::KBlockSize = 20;
// Delay between generations (microseconds)
// Actual minimum is 1/10s on WINS
const TInt CDirectDisplayLife::KGenerationInterval = 1000*1000;
// X & Y origins of upper left of cell display
const TInt CDirectDisplayLife::iXOrigin = 50;
const TInt CDirectDisplayLife::iYOrigin = 30;

CDirectDisplayLife::CDirectDisplayLife(RWsSession& aClient, 
                                       RWindow& aWindow,
                                       CLifeEngine& aLifeEngine)
: CTimer(CActive::EPriorityStandard),
    iClient(aClient),
    iWindow(aWindow),
    iLifeEngine(aLifeEngine)
    {
    }

CDirectDisplayLife::~CDirectDisplayLife()
    {
    Cancel();
    delete iDirectScreenAccess;
    }

void CDirectDisplayLife::ConstructL()
    {
    CTimer::ConstructL();
    // Create the DSA object
    iDirectScreenAccess = CDirectScreenAccess::NewL(
        iClient,                // WS session
        *(CCoeEnv::Static()->ScreenDevice()),        // CWsScreenDevice
        iWindow,                // RWindowBase
        *this                   // MDirectScreenAccess
        );

    CActiveScheduler::Add(this);
    }

// Start game display
void CDirectDisplayLife::StartL()
    {
    // Initialise DSA
    iDirectScreenAccess -> StartL();
    // Get graphics context for it
    iGc = iDirectScreenAccess -> Gc();
    iGc -> SetBrushStyle(CGraphicsContext::ESolidBrush);
    // Get region that DSA can draw in
    iRegion = iDirectScreenAccess -> DrawingRegion();
    // Set the display to clip to this region
    iGc -> SetClippingRegion(iRegion); 

    After(TTimeIntervalMicroSeconds32(KGenerationInterval));
    }
    
// Implement MDirectScreenAccess
void CDirectDisplayLife::Restart(RDirectScreenAccess::TTerminationReasons /*aReason*/)
    {
    // Restart display
    // Note that this will result in the clipping region being updated
    // so that menus, overlaying dialogs, etc. will not be drawn over
    StartL();
    }

void CDirectDisplayLife::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/)
    {
    // Cancel timer and display
    Cancel();
    }

// Draw cells using DSA
void CDirectDisplayLife::RunL()
    {
    // Update engine
    iLifeEngine.AddGeneration();
    const TCellArray& iCells = iLifeEngine.GetCellArray();

    // Force screen update: this required for WINS, but may
    // not be for all hardware
    iDirectScreenAccess->ScreenDevice()->Update();

    // Loop through cells drawing each
    TRect drawBlock(iXOrigin, iYOrigin, iXOrigin+KBlockSize,iYOrigin+KBlockSize);
    for (int y=0; y<DIM_Y_ARRAY; y++)
        {
        for (int x=0; x<DIM_X_ARRAY; x++)
            {
            if (iCells[x][y])
                iGc -> SetBrushColor(KRgbBlue);
            else
                iGc -> SetBrushColor(KRgbYellow);
            iGc -> DrawRect(drawBlock);
            drawBlock.Move(KBlockSize,0);
            }
        drawBlock.iTl.iX = iXOrigin;
        drawBlock.iBr.iX = iXOrigin+KBlockSize;
        drawBlock.Move(0,KBlockSize);
        }
    iClient.Flush();
    // Renew request
    After(TTimeIntervalMicroSeconds32(KGenerationInterval));
    }

void CDirectDisplayLife::DoCancel()
    {
    // Cancel timer
    CTimer::DoCancel();
    // Cancel DSA
    iDirectScreenAccess -> Cancel();
    }

CLifeEngine.h

// CLifeEngine.h
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

#if !defined(__CLIFEENGINE_H__)
#define __CLIFEENGINE_H__

#include <e32base.h>

// Cell array dimensions
const TInt DIM_X_ARRAY = 16;
const TInt DIM_Y_ARRAY = 8;

// Cell array type
typedef TBool TCellArray[DIM_X_ARRAY][DIM_Y_ARRAY];

// A "Game of Life" engine
// After John Conway, Scientific American 223 (October 1970): 120-123
class CLifeEngine: public CBase
    {
public:
    // Initalise engine with random seed
    CLifeEngine(const TInt64& aSeed);
    // Moves forward one generation
    void AddGeneration();
    // Gets cell array
    const TCellArray& GetCellArray() const
        {return iCellArray;}
    // Resets all cells to random state
    void Reset();

private:
    // Gets number of neighbors for cell x,y
    TInt NumNeighbors(TInt x, TInt y);

private:
    // Random num generator seed
    TInt64 iSeed;
    // Cell array
    TCellArray iCellArray;
    // Temporary working cell array
    TCellArray iTempCellArray;
    };


#endif

CLifeEngine.cpp

// CLifeEngine.cpp
//
// Copyright (c) 2005 Symbian Softwares Ltd.  All rights reserved.
//

#include <e32math.h>

#include "CLifeEngine.h"

CLifeEngine::CLifeEngine(const TInt64& aSeed)
: iSeed(aSeed)
    {
    Reset();
    }

// Sets random initial cell states
void CLifeEngine::Reset()
    {
    for (TInt y=0; y < DIM_Y_ARRAY; y++)
        for (TInt x=0; x < DIM_X_ARRAY; x++)
            iCellArray[x][y] = (Math::Rand(iSeed) > KMaxTInt/2) ? ETrue : EFalse;
    }

// Loops through cell array, storing a version altered according to the 
// game of life, in a temporary array
void CLifeEngine::AddGeneration()
    {
    TInt numNeighbours;
    
    for (TInt y=0; y < DIM_Y_ARRAY; y++)
        {
        for (TInt x=0; x < DIM_X_ARRAY; x++)
            {
            numNeighbours=NumNeighbors(x,y);
            
            if (iCellArray[x][y])
                // Filled cell
                {
                if ((numNeighbours == 2) || (numNeighbours == 3))
                    iTempCellArray[x][y]=ETrue;
                else
                    iTempCellArray[x][y]=EFalse;
                }
            else
                // Empty cell
                {
                if (numNeighbours == 3)
                    iTempCellArray[x][y]=ETrue;
                else
                    iTempCellArray[x][y]=EFalse;
                }
            }
        }
    
    for (TInt y2 =0; y2 < DIM_Y_ARRAY; y2++)
        for (TInt x2=0; x2 < DIM_X_ARRAY; x2++)
            iCellArray[x2][y2]=iTempCellArray[x2][y2];
    }


// Gets the number of adjacent cells to the specified cell
TInt CLifeEngine::NumNeighbors(TInt x, TInt y)
    {
    TInt numNeighbors=0;
    TInt i =0;

    // Get neighbors to the left
    if ((x-1) >= 0)
        for (i=y-1; i <= y+1; i++)
            if ((i >= 0) && (i < DIM_Y_ARRAY))
                if (iCellArray[x-1][i])
                    numNeighbors++;
    
    // Get neighbors to the right
    if (x+1 < DIM_X_ARRAY)
        for (i=y-1; i <= y+1; i++)
            if ((i >= 0) && (i < DIM_Y_ARRAY))
                if (iCellArray[x+1][i])
                    numNeighbors++;
    
    // Get neighbors straight above
    if ((y-1) >= 0)
        if (iCellArray[x][y-1])
            numNeighbors++;
    
    // Get neighbors straight below
    if ((y+1) < DIM_Y_ARRAY)
        if (iCellArray[x][y+1])
            numNeighbors++;
    
    return numNeighbors;
    }

[Top]


Note for developers

While the DSA is in operation, the client should not make any call to the Window Server (WSERV) that will affect the visible area of the window in which the DSA is taking place. If this happens, it will cause a temporary deadlock (since the client will be waiting for WSERV to make the requested window rearrangement, and WSERV will be waiting for the client to acknowledge that the DSA has aborted).