Direct
: Direct Screen Access
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.
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:
CDirectDisplayLife
: the object that draws the grid
through a CDirectScreenAccess
, and which implements the API's
MDirectScreenAccess
callback interface, so that the window server
can indicate when conditions (e.g. overlaying windows) change
CExampleAppView
: the application's window, which owns
the CDirectDisplayLife
object
CExampleAppUi
: handles commands and calls the view
appropriately
Commands are given to the example through its Life
menu. The commands are:
Start
: starts or restarts the life display
Test overlay
: simulates a window from another
program being placed partially over the display area. The display area is then
clipped appropriately, so that the upper window is not overwritten
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
//
// 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.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
//
// 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"; }
};
}
#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
//
// Copyright (c) 2005 Symbian Softwares Ltd. All rights reserved.
//
#define EExampleCmd1 0x1001
#define EExampleCmd2 0x1002
// 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
//
// 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
//
// 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
//
// 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
//
// 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
//
// 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;
}
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).