Commit 10ab421d authored by Ryan C. Gordon's avatar Ryan C. Gordon

Added S60 port.

--HG--
branch : SDL-1.2
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/branches/SDL-1.2%402375
parent 6fb707a2
==============================================================================
Using the Simple DirectMedia Layer with S60 3.x / Symbian 9.x
==============================================================================
These instuctions are for people developing for S60 3.x. S60 3.x
uses Symbian OS so you need S60 SDK.
extract "symbian.zip" into this folder.
go to symbian folder
bldmake bldfiles
abld build
That produces WINSCW and ARMV5 versions of sdl.dll runtime library
and sdl.lib for development.
Eaudiolib.lib and dll are generated as well, and must be delivered
along SDL as it uses it for audio.
There are certain problems with GCC compiler when building for
target, it may compile or binaries are buggy - please use RVCT
compiler as it works and produces far more effient code.
Its likely that SDL application should be integrated into S60
work and behave well there. So there is CSDL class (sdlepocapi.h)
to make this easy. If you do porting from other system, then
implement a S60 application and use CSDL class, they you may
not need to modify original SDL code at all!
......@@ -46,6 +46,9 @@ SDL 1.2.12 is a minor bug fix release.
<P>
Support for Nokia 9210 "EPOC" driver has been removed from the main SDL code.
</P>
<P>
Unofficial support for the S60/SymbianOS platform has been added.
</P>
</BLOCKQUOTE>
<H3> Unix Notes </H3>
......
......@@ -32,6 +32,8 @@
#include "SDL_config_macos.h"
#elif defined(__MACOSX__)
#include "SDL_config_macosx.h"
#elif defined(__SYMBIAN32__)
#include "SDL_config_symbian.h" /* must be before win32! */
#elif defined(__WIN32__)
#include "SDL_config_win32.h"
#elif defined(__OS2__)
......
......@@ -224,7 +224,6 @@
/* Enable various threading systems */
#undef SDL_THREAD_BEOS
#undef SDL_THREAD_DC
#undef SDL_THREAD_EPOC
#undef SDL_THREAD_OS2
#undef SDL_THREAD_PTH
#undef SDL_THREAD_PTHREAD
......@@ -237,7 +236,6 @@
#undef SDL_TIMER_BEOS
#undef SDL_TIMER_DC
#undef SDL_TIMER_DUMMY
#undef SDL_TIMER_EPOC
#undef SDL_TIMER_MACOS
#undef SDL_TIMER_MINT
#undef SDL_TIMER_OS2
......@@ -255,7 +253,6 @@
#undef SDL_VIDEO_DRIVER_DIRECTFB
#undef SDL_VIDEO_DRIVER_DRAWSPROCKET
#undef SDL_VIDEO_DRIVER_DUMMY
#undef SDL_VIDEO_DRIVER_EPOC
#undef SDL_VIDEO_DRIVER_FBCON
#undef SDL_VIDEO_DRIVER_GAPI
#undef SDL_VIDEO_DRIVER_GEM
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
/*
Symbian version Markus Mertama
*/
#ifndef _SDL_CONFIG_SYMBIAN_H
#define _SDL_CONFIG_SYMBIAN_H
#include "SDL_platform.h"
/* This is the minimal configuration that can be used to build SDL */
#include <stdarg.h>
#include <stddef.h>
#ifdef __GCCE__
#define SYMBIAN32_GCCE
#endif
#ifndef _SIZE_T_DEFINED
typedef unsigned int size_t;
#endif
#ifndef _INTPTR_T_DECLARED
typedef unsigned int uintptr_t;
#endif
#ifndef _INT8_T_DECLARED
typedef signed char int8_t;
#endif
#ifndef _UINT8_T_DECLARED
typedef unsigned char uint8_t;
#endif
#ifndef _INT16_T_DECLARED
typedef signed short int16_t;
#endif
#ifndef _UINT16_T_DECLARED
typedef unsigned short uint16_t;
#endif
#ifndef _INT32_T_DECLARED
typedef signed int int32_t;
#endif
#ifndef _UINT32_T_DECLARED
typedef unsigned int uint32_t;
#endif
#ifndef _INT64_T_DECLARED
typedef signed long long int64_t;
#endif
#ifndef _UINT64_T_DECLARED
typedef unsigned long long uint64_t;
#endif
#define SDL_AUDIO_DRIVER_EPOCAUDIO 1
/* Enable the stub cdrom driver (src/cdrom/dummy/\*.c) */
#define SDL_CDROM_DISABLED 1
/* Enable the stub joystick driver (src/joystick/dummy/\*.c) */
#define SDL_JOYSTICK_DISABLED 1
/* Enable the stub shared object loader (src/loadso/dummy/\*.c) */
#define SDL_LOADSO_DISABLED 1
#define SDL_THREAD_SYMBIAN 1
#define SDL_VIDEO_DRIVER_EPOC 1
#define SDL_VIDEO_OPENGL 0
#define SDL_HAS_64BIT_TYPE 1
#define HAVE_LIBC 1
#define HAVE_STDIO_H 1
#define STDC_HEADERS 1
#define HAVE_STRING_H 1
#define HAVE_CTYPE_H 1
#define HAVE_MATH_H 1
#define HAVE_MALLOC 1
#define HAVE_CALLOC 1
#define HAVE_REALLOC 1
#define HAVE_FREE 1
//#define HAVE_ALLOCA 1
#define HAVE_QSORT 1
#define HAVE_ABS 1
#define HAVE_MEMSET 1
#define HAVE_MEMCPY 1
#define HAVE_MEMMOVE 1
#define HAVE_MEMCMP 1
#define HAVE_STRLEN 1
#define HAVE__STRUPR 1
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
#define HAVE_ITOA 1
#define HAVE_STRTOL 1
#define HAVE_STRTOUL 1
#define HAVE_STRTOLL 1
#define HAVE_STRTOD 1
#define HAVE_ATOI 1
#define HAVE_ATOF 1
#define HAVE_STRCMP 1
#define HAVE_STRNCMP 1
#define HAVE__STRICMP 1
#define HAVE__STRNICMP 1
#define HAVE_SSCANF 1
#define HAVE_STDARG_H 1
#define HAVE_STDDEF_H 1
#endif /* _SDL_CONFIG_SYMBIAN_H */
......@@ -91,7 +91,9 @@ typedef uint32_t Uint32;
#ifdef SDL_HAS_64BIT_TYPE
typedef int64_t Sint64;
#ifndef SYMBIAN32_GCCE
typedef uint64_t Uint64;
#endif
#else
/* This is really just a hack to prevent the compiler from complaining */
typedef struct {
......
......@@ -45,7 +45,7 @@ struct SDL_Thread;
typedef struct SDL_Thread SDL_Thread;
/* Create a thread */
#if (defined(__WIN32__) && !defined(HAVE_LIBC)) || defined(__OS2__)
#if ((defined(__WIN32__) && !defined(HAVE_LIBC)) || defined(__OS2__)) && !defined(__SYMBIAN32__)
/*
We compile SDL into a DLL on OS/2. This means, that it's the DLL which
creates a new thread for the calling process with the SDL_CreateThread()
......
......@@ -83,11 +83,15 @@
#endif
#endif /* SDLCALL */
/* Removed DECLSPEC on Symbian OS because SDL cannot be a DLL in EPOC */
#ifdef __SYMBIAN32__
#ifndef EKA2
#undef DECLSPEC
#define DECLSPEC
#endif /* __SYMBIAN32__ */
#elif !defined(__WINS__)
#undef DECLSPEC
#define DECLSPEC __declspec(dllexport)
#endif //EKA2
#endif //__SYMBIAN32__
/* Force structure packing at 4 byte alignment.
This is necessary if the header is included in code which has structure
......@@ -116,7 +120,7 @@
#if defined(_MSC_VER) || defined(__BORLANDC__) || \
defined(__DMC__) || defined(__SC__) || \
defined(__WATCOMC__) || defined(__LCC__) || \
defined(__DECC)
defined(__DECC) || defined(__EABI__)
#ifndef __inline__
#define __inline__ __inline
#endif
......
......@@ -323,7 +323,7 @@ unsigned _System LibMain(unsigned hmod, unsigned termination)
}
#endif /* __WATCOMC__ */
#elif defined(__WIN32__)
#elif defined(__WIN32__) && !defined(__SYMBIAN32__)
#if !defined(HAVE_LIBC) || (defined(__WATCOMC__) && defined(BUILD_DLL))
/* Need to include DllMain() on Watcom C for some reason.. */
......
......@@ -106,6 +106,9 @@ static AudioBootStrap *bootstrap[] = {
#endif
#if SDL_AUDIO_DRIVER_DART
&DART_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_EPOCAUDIO
&EPOCAudio_bootstrap,
#endif
NULL
};
......@@ -545,7 +548,7 @@ int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
switch (audio->opened) {
case 1:
/* Start the audio thread */
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) && !defined(__SYMBIAN32__)
#undef SDL_CreateThread
audio->thread = SDL_CreateThread(SDL_RunAudio, audio, NULL, NULL);
#else
......
......@@ -171,6 +171,9 @@ extern AudioBootStrap MMEAUDIO_bootstrap;
#if SDL_AUDIO_DRIVER_DART
extern AudioBootStrap DART_bootstrap;
#endif
#if SDL_AUDIO_DRIVER_EPOCAUDIO
extern AudioBootStrap EPOCAudio_bootstrap;
#endif
/* This is the current audio device */
extern SDL_AudioDevice *current_audio;
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_epocaudio.cpp
Epoc based SDL audio driver implementation
Markus Mertama
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_epocaudio.c,v 0.0.0.0 2001/06/19 17:19:56 hercules Exp $";
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include "epoc_sdl.h"
#include <e32hal.h>
extern "C" {
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_audiomem.h"
#include "SDL_audio_c.h"
#include "SDL_timer.h"
#include "SDL_audiodev_c.h"
}
#include "SDL_epocaudio.h"
#include "streamplayer.h"
//#define DEBUG_AUDIO
/* Audio driver functions */
static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec);
static void EPOC_WaitAudio(SDL_AudioDevice *thisdevice);
static void EPOC_PlayAudio(SDL_AudioDevice *thisdevice);
static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice *thisdevice);
static void EPOC_CloseAudio(SDL_AudioDevice *thisdevice);
static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice);
static int Audio_Available(void);
static SDL_AudioDevice *Audio_CreateDevice(int devindex);
static void Audio_DeleteDevice(SDL_AudioDevice *device);
//void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len);
#ifdef __WINS__
#define DODUMP
#endif
#ifdef DODUMP
NONSHARABLE_CLASS(TDump)
{
public:
TInt Open();
void Close();
void Dump(const TDesC8& aDes);
private:
RFile iFile;
RFs iFs;
};
TInt TDump::Open()
{
TInt err = iFs.Connect();
if(err == KErrNone)
{
#ifdef __WINS__
_LIT(target, "C:\\sdlau.raw");
#else
_LIT(target, "E:\\sdlau.raw");
#endif
err = iFile.Replace(iFs, target, EFileWrite);
}
return err;
}
void TDump::Close()
{
iFile.Close();
iFs.Close();
}
void TDump::Dump(const TDesC8& aDes)
{
iFile.Write(aDes);
}
#endif
NONSHARABLE_CLASS(CSimpleWait) : public CTimer
{
public:
void Wait(TTimeIntervalMicroSeconds32 aWait);
static CSimpleWait* NewL();
private:
CSimpleWait();
void RunL();
};
CSimpleWait* CSimpleWait::NewL()
{
CSimpleWait* wait = new (ELeave) CSimpleWait();
CleanupStack::PushL(wait);
wait->ConstructL();
CleanupStack::Pop();
return wait;
}
void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait)
{
After(aWait);
CActiveScheduler::Start();
}
CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard)
{
CActiveScheduler::Add(this);
}
void CSimpleWait::RunL()
{
CActiveScheduler::Stop();
}
const TInt KAudioBuffers(2);
NONSHARABLE_CLASS(CEpocAudio) : public CBase, public MStreamObs, public MStreamProvider
{
public:
static void* NewL(TInt BufferSize, TInt aFill);
inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice);
static void Free(SDL_AudioDevice* thisdevice);
void Wait();
void Play();
// void SetBuffer(const TDesC8& aBuffer);
void ThreadInitL(TAny* aDevice);
void Open(TInt iRate, TInt iChannels, TUint32 aType, TInt aBytes);
~CEpocAudio();
TUint8* Buffer();
TBool SetPause(TBool aPause);
#ifdef DODUMP
void Dump(const TDesC8& aBuf) {iDump.Dump(aBuf);}
#endif
private:
CEpocAudio(TInt aBufferSize);
void Complete(TInt aState, TInt aError);
TPtrC8 Data();
void ConstructL(TInt aFill);
private:
TInt iBufferSize;
CStreamPlayer* iPlayer;
TInt iBufferRate;
TInt iRate;
TInt iChannels;
TUint32 iType;
TInt iPosition;
TThreadId iTid;
TUint8* iAudioPtr;
TUint8* iBuffer;
// TTimeIntervalMicroSeconds iStart;
TTime iStart;
TInt iTune;
CSimpleWait* iWait;
#ifdef DODUMP
TDump iDump;
#endif
};
inline CEpocAudio& CEpocAudio::Current(SDL_AudioDevice* thisdevice)
{
return *static_cast<CEpocAudio*>((void*)thisdevice->hidden);
}
/*
TBool EndSc(TAny*)
{
CActiveScheduler::Stop();
}
LOCAL_C void CleanScL()
{
CIdle* d = CIdle::NewLC(CActive:::EPriorityIdle);
d->Start(TCallBack(EndSc));
CActiveScheduler::Start();
}
*/
void CEpocAudio::Free(SDL_AudioDevice* thisdevice)
{
CEpocAudio* ea = static_cast<CEpocAudio*>((void*)thisdevice->hidden);
if(ea)
{
ASSERT(ea->iTid == RThread().Id());
delete ea;
thisdevice->hidden = NULL;
CActiveScheduler* as = CActiveScheduler::Current();
ASSERT(as->StackDepth() == 0);
delete as;
CActiveScheduler::Install(NULL);
}
ASSERT(thisdevice->hidden == NULL);
}
CEpocAudio::CEpocAudio(TInt aBufferSize) : iBufferSize(aBufferSize), iPosition(-1)
{
}
void* CEpocAudio::NewL(TInt aBufferSize, TInt aFill)
{
CEpocAudio* eAudioLib = new (ELeave) CEpocAudio(aBufferSize);
CleanupStack::PushL(eAudioLib);
eAudioLib->ConstructL(aFill);
CleanupStack::Pop();
return eAudioLib;
}
void CEpocAudio::ConstructL(TInt aFill)
{
iBuffer = (TUint8*) User::AllocL(KAudioBuffers * iBufferSize);
memset(iBuffer, aFill, KAudioBuffers * iBufferSize);
iAudioPtr = iBuffer;
}
TBool CEpocAudio::SetPause(TBool aPause)
{
if(aPause && iPosition >= 0)
{
iPosition = -1;
if(iPlayer != NULL)
iPlayer->Stop();
}
if(!aPause && iPosition < 0)
{
iPosition = 0;
if(iPlayer != NULL)
iPlayer->Start();
}
return iPosition < 0;
}
void CEpocAudio::ThreadInitL(TAny* aDevice)
{
iTid = RThread().Id();
CActiveScheduler* as = new (ELeave) CActiveScheduler();
CActiveScheduler::Install(as);
EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation)EPOC_CloseAudio, aDevice));
iWait = CSimpleWait::NewL();
iPlayer = new (ELeave) CStreamPlayer(*this, *this);
iPlayer->ConstructL();
iPlayer->OpenStream(iRate, iChannels, iType);
#ifdef DODUMP
User::LeaveIfError(iDump.Open());
#endif
}
TUint8* CEpocAudio::Buffer()
{
iStart.UniversalTime();
// iStart = iPlayer->Position();
return iAudioPtr;
}
CEpocAudio::~CEpocAudio()
{
if(iWait != NULL)
iWait->Cancel();
delete iWait;
if(iPlayer != NULL)
iPlayer->Close();
delete iPlayer;
delete iBuffer;
}
void CEpocAudio::Complete(TInt aState, TInt aError)
{
if(aState == MStreamObs::EClose)
{
}
if(iPlayer->Closed())
return;
switch(aError)
{
case KErrUnderflow:
case KErrInUse:
iPlayer->Start();
break;
case KErrAbort:
iPlayer->Open();
}
}
void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len)
{
#ifdef DODUMP
const TPtrC8 buf((TUint8*)data, len);
CEpocAudio::Current(thisdevice).Dump(buf);
#endif
}
const TInt KClip(256);
TPtrC8 CEpocAudio::Data()
{
if(iPosition < 0)
return KNullDesC8();
TPtrC8 data(iAudioPtr + iPosition, KClip);
#ifdef DODUMP
iDump.Dump(data);
#endif
iPosition += KClip;
if(iPosition >= iBufferSize)
{
/* if(iAudioPtr == iBuffer)
iAudioPtr = iBuffer + iBufferSize;
else
iAudioPtr = iBuffer;
*/
iAudioPtr += iBufferSize;
if((iAudioPtr - iBuffer) >= KAudioBuffers * iBufferSize)
iAudioPtr = iBuffer;
iPosition = -1;
if(iWait->IsActive())
{
iWait->Cancel();
CActiveScheduler::Stop();
}
}
return data;
}
void CEpocAudio::Play()
{
iPosition = 0;
}
void CEpocAudio::Wait()
{
if(iPosition >= 0 /*&& iPlayer->Playing()*/)
{
const TInt64 bufMs = TInt64(iBufferSize - KClip) * TInt64(1000000);
const TInt64 specTime = bufMs / TInt64(iRate * iChannels * 2);
iWait->After(specTime);
CActiveScheduler::Start();
TTime end;
end.UniversalTime();
const TTimeIntervalMicroSeconds delta = end.MicroSecondsFrom(iStart);
// const TTimeIntervalMicroSeconds end = iPlayer->Position();
const TInt diff = specTime - delta.Int64();
if(diff > 0 && diff < 200000)
{
User::After(diff);
}
}
else
{
User::After(10000);
// iWait->Wait(10000); //just give some time...
}
}
void CEpocAudio::Open(TInt aRate, TInt aChannels, TUint32 aType, TInt aBytes)
{
iRate = aRate;
iChannels = aChannels;
iType = aType;
iBufferRate = iRate * iChannels * aBytes; //1/x
}
/* Audio driver bootstrap functions */
AudioBootStrap EPOCAudio_bootstrap = {
"epoc\0\0\0",
"EPOC streaming audio\0\0\0",
Audio_Available,
Audio_CreateDevice
};
static SDL_AudioDevice *Audio_CreateDevice(int /*devindex*/)
{
SDL_AudioDevice *thisdevice;
/* Initialize all variables that we clean on shutdown */
thisdevice = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
if ( thisdevice ) {
memset(thisdevice, 0, (sizeof *thisdevice));
thisdevice->hidden = NULL; /*(struct SDL_PrivateAudioData *)
malloc((sizeof thisdevice->hidden)); */
}
if ( (thisdevice == NULL) /*|| (thisdevice->hidden == NULL) */) {
SDL_OutOfMemory();
if ( thisdevice ) {
free(thisdevice);
}
return(0);
}
// memset(thisdevice->hidden, 0, (sizeof *thisdevice->hidden));
/* Set the function pointers */
thisdevice->OpenAudio = EPOC_OpenAudio;
thisdevice->WaitAudio = EPOC_WaitAudio;
thisdevice->PlayAudio = EPOC_PlayAudio;
thisdevice->GetAudioBuf = EPOC_GetAudioBuf;
thisdevice->CloseAudio = EPOC_CloseAudio;
thisdevice->ThreadInit = EPOC_ThreadInit;
thisdevice->free = Audio_DeleteDevice;
return thisdevice;
}
static void Audio_DeleteDevice(SDL_AudioDevice *device)
{
//free(device->hidden);
free(device);
}
static int Audio_Available(void)
{
return(1); // Audio stream modules should be always there!
}
static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec)
{
SDL_TRACE("SDL:EPOC_OpenAudio");
TUint32 type = KMMFFourCCCodePCM16;
TInt bytes = 2;
switch(spec->format)
{
case AUDIO_U16LSB:
type = KMMFFourCCCodePCMU16;
break;
case AUDIO_S16LSB:
type = KMMFFourCCCodePCM16;
break;
case AUDIO_U16MSB:
type = KMMFFourCCCodePCMU16B;
break;
case AUDIO_S16MSB:
type = KMMFFourCCCodePCM16B;
break;
//8 bit not supported!
case AUDIO_U8:
case AUDIO_S8:
default:
spec->format = AUDIO_S16LSB;
};
if(spec->channels > 2)
spec->channels = 2;
spec->freq = CStreamPlayer::ClosestSupportedRate(spec->freq);
/* Allocate mixing buffer */
const TInt buflen = spec->size;// * bytes * spec->channels;
// audiobuf = NULL;
TRAPD(err, thisdevice->hidden = static_cast<SDL_PrivateAudioData*>(CEpocAudio::NewL(buflen, spec->silence)));
if(err != KErrNone)
return -1;
CEpocAudio::Current(thisdevice).Open(spec->freq, spec->channels, type, bytes);
CEpocAudio::Current(thisdevice).SetPause(ETrue);
// isSDLAudioPaused = 1;
thisdevice->enabled = 0; /* enable only after audio engine has been initialized!*/
/* We're ready to rock and roll. :-) */
return(0);
}
static void EPOC_CloseAudio(SDL_AudioDevice* thisdevice)
{
#ifdef DEBUG_AUDIO
SDL_TRACE("Close audio\n");
#endif
CEpocAudio::Free(thisdevice);
}
static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice)
{
SDL_TRACE("SDL:EPOC_ThreadInit");
CEpocAudio::Current(thisdevice).ThreadInitL(thisdevice);
RThread().SetPriority(EPriorityMore);
thisdevice->enabled = 1;
}
/* This function waits until it is possible to write a full sound buffer */
static void EPOC_WaitAudio(SDL_AudioDevice* thisdevice)
{
#ifdef DEBUG_AUDIO
SDL_TRACE1("wait %d audio\n", CEpocAudio::AudioLib().StreamPlayer(KSfxChannel).SyncTime());
TInt tics = User::TickCount();
#endif
CEpocAudio::Current(thisdevice).Wait();
#ifdef DEBUG_AUDIO
TInt ntics = User::TickCount() - tics;
SDL_TRACE1("audio waited %d\n", ntics);
SDL_TRACE1("audio at %d\n", tics);
#endif
}
static void EPOC_PlayAudio(SDL_AudioDevice* thisdevice)
{
if(CEpocAudio::Current(thisdevice).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED))
SDL_Delay(500); //hold on the busy loop
else
CEpocAudio::Current(thisdevice).Play();
#ifdef DEBUG_AUDIO
SDL_TRACE("buffer has audio data\n");
#endif
#ifdef DEBUG_AUDIO
SDL_TRACE1("Wrote %d bytes of audio data\n", buflen);
#endif
}
static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice* thisdevice)
{
return CEpocAudio::Current(thisdevice).Buffer();
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_epocaudio.h,v 1.1.2.2 2001/02/10 07:20:03 hercules Exp $";
#endif
#ifndef _SDL_EPOCAUDIO_H
#define _SDL_EPOCAUDIO_H
extern "C" {
#include "SDL_sysaudio.h"
}
#endif /* _SDL_EPOCAUDIO_H */
#include "streamplayer.h"
#include<mda/common/audio.h>
const TInt KMaxVolume(256);
LOCAL_C TInt GetSampleRate(TInt aRate)
{
switch(aRate)
{
case 8000: return TMdaAudioDataSettings::ESampleRate8000Hz;
case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
}
return KErrNotFound;
}
LOCAL_C TInt GetChannels(TInt aChannels)
{
switch(aChannels)
{
case 1: return TMdaAudioDataSettings::EChannelsMono;
case 2: return TMdaAudioDataSettings::EChannelsStereo;
}
return KErrNotFound;
}
TInt CStreamPlayer::ClosestSupportedRate(TInt aRate)
{
if(aRate > 96000)
return 96000;
TInt rate = aRate;
while(GetSampleRate(rate) == KErrNotFound)
{
++rate;
}
return rate;
}
CStreamPlayer::CStreamPlayer(MStreamProvider& aProvider, MStreamObs& aObs) :
iProvider(aProvider), iObs(aObs), iVolume(KMaxVolume)
{
}
CStreamPlayer::~CStreamPlayer()
{
iState |= EDied;
if(iState & EInited)
Close();
User::After(100000); //wait buffer to be flushed
ASSERT(iPtr.Length() == 0);
delete iStream;
}
void CStreamPlayer::ConstructL()
{
iStream = CMdaAudioOutputStream::NewL(*this, EMdaPriorityMax);
iSilence.SetMax();
iSilence.FillZ();
}
TInt CStreamPlayer::OpenStream(TInt aRate, TInt aChannels, TUint32 aType)
{
Close();
iType = aType;
iRate = GetSampleRate(aRate);
if(iRate == KErrNotFound)
return KErrNotSupported;
iChannels = GetChannels(aChannels);
if(iChannels == KErrNotFound)
return KErrNotSupported;
Open();
return KErrNone;
}
TInt CStreamPlayer::MaxVolume() const
{
return KMaxVolume;
}
void CStreamPlayer::SetVolume(TInt aNew)
{
const TInt maxi = MaxVolume();
if(aNew > maxi)
return;
if(aNew < 0)
return;
iVolume = aNew;
iState |= EVolumeChange;
}
TInt CStreamPlayer::Volume() const
{
return iVolume;
}
void CStreamPlayer::Open()
{
TMdaAudioDataSettings audioSettings;
audioSettings.Query();
audioSettings.iCaps = TMdaAudioDataSettings::ERealTime |
TMdaAudioDataSettings::ESampleRateFixed;
audioSettings.iSampleRate = iRate;
audioSettings.iChannels = iChannels;
audioSettings.iFlags = TMdaAudioDataSettings::ENoNetworkRouting;
audioSettings.iVolume = 0;
iState &= ~EStopped;
iStream->Open(&audioSettings);
}
void CStreamPlayer::Stop()
{
if(iState & (EStarted | EInited))
{
Close();
iState |= EStopped;
}
}
void CStreamPlayer::Start()
{
if(iPtr.Length() == 0)
{
iState |= EStarted;
if(iState & EInited)
{
Request();
}
else if(iState & EStopped)
{
Open();
}
}
}
void CStreamPlayer::Close()
{
iState &= ~EInited;
iStream->Stop();
iState &= ~EStarted;
}
void CStreamPlayer::Request()
{
if(iState & EInited)
{
iPtr.Set(KNullDesC8);
if(iState & EVolumeChange)
{
const TReal newVol = iVolume;
const TReal newMax = MaxVolume();
const TInt maxVol = iStream->MaxVolume();
const TReal max = static_cast<TReal>(maxVol);
const TReal newvolume = (newVol * max) / newMax;
const TInt vol = static_cast<TReal>(newvolume);
iStream->SetVolume(vol);
iState &= ~EVolumeChange;
}
if(iState & EStarted)
{
iPtr.Set(iProvider.Data());
}
if(iPtr.Length() == 0)
{
iPtr.Set(iSilence);
}
TRAPD(err, iStream->WriteL(iPtr));
if(err != KErrNone)
{
iObs.Complete(MStreamObs::EWrite, err);
}
/* else
{
iProvider.Written(iPtr.Length());
}*/
}
}
void CStreamPlayer::SetCapsL()
{
iStream->SetDataTypeL(iType);
iStream->SetAudioPropertiesL(iRate, iChannels);
}
void CStreamPlayer::MaoscOpenComplete(TInt aError)
{
if(aError == KErrNone)
{
TRAPD(err, SetCapsL());
if(err == KErrNone)
{
iStream->SetPriority(EPriorityNormal, EMdaPriorityPreferenceTime);
iState |= EInited;
SetVolume(Volume());
if(iState & EStarted)
{
Request();
}
}
aError = err;
}
if(!(iState & EDied))
iObs.Complete(MStreamObs::EInit, aError);
}
void CStreamPlayer::MaoscBufferCopied(TInt aError, const TDesC8& /*aBuffer*/)
{
iPtr.Set(KNullDesC8);
if(aError == KErrNone)
{
if(iState & EInited)
Request();
else
iStream->Stop();
}
else if(!(iState & EDied))
iObs.Complete(MStreamObs::EPlay, aError);
}
void CStreamPlayer::MaoscPlayComplete(TInt aError)
{
iPtr.Set(KNullDesC8);
iState &= ~EStarted;
if(!(iState & EDied))
iObs.Complete(MStreamObs::EClose, aError);
}
TBool CStreamPlayer::Playing() const
{
return (iState & EInited) && (iState & EStarted);
}
TBool CStreamPlayer::Closed() const
{
return !(iState & EInited) && !(iState & EDied);
}
/*
void CStreamPlayer::Request()
{
SetActive();
TRequestStatus* s = &iStatus;
User::RequestComplete(s, KErrNone);
}
// iTimer.After(0);
*/
#ifndef STREAMPLAYER_H
#define STREAMPLAYER_H
#include<MdaAudioOutputStream.h>
const TInt KSilenceBuffer = 256;
class MStreamObs
{
public:
enum
{
EInit,
EPlay,
EWrite,
EClose,
};
virtual void Complete(TInt aState, TInt aError) = 0;
};
class MStreamProvider
{
public:
virtual TPtrC8 Data() = 0;
};
NONSHARABLE_CLASS(CStreamPlayer) : public CBase, public MMdaAudioOutputStreamCallback
{
public:
CStreamPlayer(MStreamProvider& aProvider, MStreamObs& aObs);
~CStreamPlayer();
void ConstructL();
static TInt ClosestSupportedRate(TInt aRate);
TInt OpenStream(TInt aRate, TInt aChannels, TUint32 aType = KMMFFourCCCodePCM16);
void SetVolume(TInt aNew);
TInt Volume() const;
TInt MaxVolume() const;
void Stop();
void Start();
void Open();
void Close();
TBool Playing() const;
TBool Closed() const;
private:
void MaoscOpenComplete(TInt aError) ;
void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
void MaoscPlayComplete(TInt aError);
private:
void Request();
void SetCapsL();
private:
MStreamProvider& iProvider;
MStreamObs& iObs;
TInt iVolume;
CMdaAudioOutputStream* iStream;
TInt iRate;
TInt iChannels;
TUint32 iType;
enum
{
ENone = 0,
EInited = 0x1,
EStarted = 0x2,
EStopped = 0x4,
EVolumeChange = 0x8,
EDied = 0x10
};
TInt iState;
TBuf8<KSilenceBuffer> iSilence;
TPtrC8 iPtr;
};
#endif
......@@ -169,7 +169,7 @@ static int SDL_StartEventThread(Uint32 flags)
/* The event thread will handle timers too */
SDL_SetTimerThreaded(2);
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC) && !defined(__SYMBIAN32__)
#undef SDL_CreateThread
SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL, NULL, NULL);
#else
......
......@@ -29,7 +29,7 @@
#include "SDL_rwops.h"
#if defined(__WIN32__)
#if defined(__WIN32__) && !defined(__SYMBIAN32__)
/* Functions to read/write Win32 API file pointers */
/* Will not use it on WinCE because stdio is buffered, it means
......@@ -372,7 +372,7 @@ SDL_RWops *SDL_RWFromFile(const char *file, const char *mode)
return NULL;
}
#if defined(__WIN32__)
#if defined(__WIN32__) && !defined(__SYMBIAN32__)
rwops = SDL_AllocRW();
if (!rwops)
return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_main.cpp
The Epoc executable startup functions
Epoc version by Hannu Viitala (hannu.j.viitala@mbnet.fi)
*/
#include <e32std.h>
#include <e32def.h>
#include <e32svr.h>
#include <e32base.h>
#include <estlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <w32std.h>
#include <apgtask.h>
#include "SDL_error.h"
#if defined(__WINS__)
#include <estw32.h>
IMPORT_C void RegisterWsExe(const TDesC &aName);
#endif
/* The prototype for the application's main() function */
#define main SDL_main
extern "C" int main (int argc, char *argv[], char *envp[]);
extern "C" void exit (int ret);
/* Epoc main function */
#ifdef __WINS__
void GetCmdLine(int& aArgc, char**& aArgv)
{
RChunk chunk;
if(chunk.OpenGlobal(RThread().Name(), ETrue) != KErrNone)
return;
TUint* ptr = (TUint*) chunk.Base();
if(ptr != NULL)
{
aArgc = (int) *(ptr); // count
aArgv = (char**) *(ptr + 1);
}
chunk.Close();
}
#endif
TInt E32Main()
{
/* Get the clean-up stack */
CTrapCleanup* cleanup = CTrapCleanup::New();
/* Arrange for multi-threaded operation */
SpawnPosixServerThread();
/* Get args and environment */
int argc=0;
char** argv=0;
char** envp=0;
#ifndef __WINS__
__crt0(argc,argv,envp);
#else
GetCmdLine(argc, argv);
#endif
/* Start the application! */
/* Create stdlib */
_REENT;
/* Set process and thread priority and name */
RThread currentThread;
RProcess thisProcess;
TParse exeName;
exeName.Set(thisProcess.FileName(), NULL, NULL);
currentThread.Rename(exeName.Name());
currentThread.SetProcessPriority(EPriorityLow);
currentThread.SetPriority(EPriorityMuchLess);
/* Call stdlib main */
int ret = main(argc, argv, envp); /* !! process exits here if there is "exit()" in main! */
/* Call exit */
//exit(ret); /* !! process exits here! */
//Markus: I do not understand above
//I commented it at let this function
//to return ret value - was it purpose
//that cleanup below is not called at all - why?
/* Free resources and return */
_cleanup(); //this is normally called at exit, I call it here, Markus
CloseSTDLIB();
delete cleanup;
#ifdef __WINS__
// User::Panic(_L("exit"), ret);
// RThread().Kill(ret); //Markus get rid of this thread
// RThread().RaiseException(EExcKill);
#endif
return ret;//Markus, or exit(ret); ??
//return(KErrNone);
}
#ifdef __WINS__
EXPORT_C TInt WinsMain()
{
return E32Main();
// return WinsMain(0, 0, 0);
}
#endif
/* Epoc dll entry point */
#if defined(__WINS__)
GLDEF_C TInt E32Dll(TDllReason)
{
return(KErrNone);
}
#endif
/*
SDL_Main.cpp
Symbian OS services for SDL
Markus Mertama
*/
#include "epoc_sdl.h"
#include"sdlepocapi.h"
#include <e32base.h>
#include <estlib.h>
#include <stdio.h>
#include <badesca.h>
#include "vectorbuffer.h"
#include <w32std.h>
#include <aknappui.h>
#include <aknapp.h>
#include "SDL_epocevents_c.h"
#include "SDL_keysym.h"
#include "dsa.h"
#ifdef SYMBIANC
#include <reent.h>
#endif
//Markus Mertama
extern SDLKey* KeyMap();
extern void ResetKeyMap();
class CCurrentAppUi;
//const TUid KSDLUid = { 0xF01F3D69 };
NONSHARABLE_CLASS(EnvUtils)
{
public:
static void DisableKeyBlocking();
static TBool Rendezvous(RThread& aThread, TRequestStatus& aStatus);
};
TInt Panic(TInt aErr, TInt aLine)
{
TBuf<64> b;
b.Format(_L("Main at %d"), aLine);
User::Panic(b, aErr);
return 0;
}
NONSHARABLE_CLASS(CCurrentAppUi) : public CAknAppUi
{
public:
static CCurrentAppUi* Cast(CEikAppUi* aUi);
void DisableKeyBlocking();
};
CCurrentAppUi* CCurrentAppUi::Cast(CEikAppUi* aUi)
{
return static_cast<CCurrentAppUi*>(aUi);
}
void CCurrentAppUi::DisableKeyBlocking()
{
SetKeyBlockMode(ENoKeyBlock);
}
class CEventQueue : public CBase, public MEventQueue
{
public:
static CEventQueue* NewL();
~CEventQueue();
public:
TInt Append(const TWsEvent& aEvent);
const TWsEvent& Shift();
void Lock();
void Unlock();
TBool HasData();
private:
TVector<TWsEvent, 64> iVector;
RCriticalSection iCS;
};
CEventQueue* CEventQueue::NewL()
{
CEventQueue* q = new (ELeave) CEventQueue();
CleanupStack::PushL(q);
User::LeaveIfError(q->iCS.CreateLocal());
CleanupStack::Pop();
return q;
}
CEventQueue::~CEventQueue()
{
iCS.Close();
}
TInt CEventQueue::Append(const TWsEvent& aEvent)
{
iCS.Wait();
const TInt err = iVector.Append(aEvent);
iCS.Signal();
return err;
}
TBool CEventQueue::HasData()
{
return iVector.Size() > 0;
}
void CEventQueue::Lock()
{
iCS.Wait();
}
void CEventQueue::Unlock()
{
iCS.Signal();
}
const TWsEvent& CEventQueue::Shift()
{
const TWsEvent& event = iVector.Shift();
return event;
}
TSdlCleanupItem::TSdlCleanupItem(TSdlCleanupOperation aOperation, TAny* aItem) :
iOperation(aOperation), iItem(aItem), iThread(RThread().Id())
{
}
class CEikonEnv;
class CSdlAppServ;
NONSHARABLE_CLASS(EpocSdlEnvData)
{
public:
void Free();
CEventQueue* iEventQueue;
TMainFunc iMain;
TInt iEpocEnvFlags;
int iArgc;
char** iArgv;
CDsa* iDsa;
CSdlAppServ* iAppSrv;
TThreadId iId;
CArrayFix<TSdlCleanupItem>* iCleanupItems;
CEikAppUi* iAppUi;
CSDL* iSdl;
};
EpocSdlEnvData* gEpocEnv;
#define MAINFUNC(x) EXPORT_C TMainFunc::TMainFunc(mainfunc##x aFunc){Mem::FillZ(iMainFunc, sizeof(iMainFunc)); iMainFunc[x - 1] = (void*) aFunc;}
MAINFUNC(1)
MAINFUNC(2)
MAINFUNC(3)
MAINFUNC(4)
MAINFUNC(5)
MAINFUNC(6)
EXPORT_C TMainFunc::TMainFunc()
{
Mem::FillZ(iMainFunc, sizeof(iMainFunc));
}
const void* TMainFunc::operator[](TInt aIndex) const
{
return iMainFunc[aIndex];
}
NONSHARABLE_CLASS(CSdlAppServ) : public CActive
{
public:
enum
{
EAppSrvNoop = CDsa::ELastDsaRequest,
EAppSrvWindowWidth,
EAppSrvWindowHeight,
EAppSrvWindowDisplayMode,
EAppSrvWindowPointerCursorMode,
EAppSrvDsaStatus,
EAppSrvStopThread,
EAppSrvWaitDsa
};
CSdlAppServ();
void ConstructL();
~CSdlAppServ();
TInt Request(TInt aService);
TInt RequestValue(TInt aService);
void Init();
void PanicMain(TInt aReason);
void PanicMain(const TDesC& aInfo, TInt aReason);
void SetObserver(MSDLObserver* aObserver);
TInt ObserverEvent(TInt aEvent, TInt aParam);
void SetParam(TInt aParam);
void HandleObserverValue(TInt aService, TInt aReturnValue, TBool aMainThread);
MSDLObserver* Observer();
private:
void RunL();
void DoCancel();
private:
const TThreadId iMainId;
RThread iAppThread;
TInt iService;
TInt iReturnValue;
RSemaphore iSema;
MSDLObserver* iObserver;
TRequestStatus* iStatusPtr;
};
CSdlAppServ::CSdlAppServ() : CActive(CActive::EPriorityHigh), iMainId(RThread().Id())
{
}
MSDLObserver* CSdlAppServ::Observer()
{
return iObserver;
}
void CSdlAppServ::SetObserver(MSDLObserver* aObserver)
{
iObserver = aObserver;
}
TInt CSdlAppServ::ObserverEvent(TInt aEvent, TInt aParam)
{
if(iObserver != NULL)
{
if(RThread().Id() == gEpocEnv->iId)
{
return iObserver->SdlThreadEvent(aEvent, aParam);
}
else if(RThread().Id() == iMainId)
{
return iObserver->SdlEvent(aEvent, aParam);
}
PANIC(KErrNotSupported);
}
return 0;
}
void CSdlAppServ::PanicMain(TInt aReason)
{
iAppThread.Panic(RThread().Name(), aReason);
}
void CSdlAppServ::PanicMain(const TDesC& aInfo, TInt aReason)
{
iAppThread.Panic(aInfo, aReason);
}
void CSdlAppServ::ConstructL()
{
CActiveScheduler::Add(this);
User::LeaveIfError(iSema.CreateLocal(1));
iStatus = KRequestPending;
iStatusPtr = &iStatus;
SetActive();
}
CSdlAppServ::~CSdlAppServ()
{
Cancel();
if(iSema.Handle() != NULL)
iSema.Signal();
iSema.Close();
iAppThread.Close();
}
TInt CSdlAppServ::Request(TInt aService)
{
if(RThread().Id() != iAppThread.Id())
{
iSema.Wait();
iService = aService;
iAppThread.RequestComplete(iStatusPtr, KErrNone);
return KErrNone;
}
return KErrBadHandle;
}
TInt CSdlAppServ::RequestValue(TInt aService)
{
Request(aService);
Request(EAppSrvNoop);
return iReturnValue;
}
void CSdlAppServ::Init()
{
PANIC_IF_ERROR(iAppThread.Open(iMainId));
}
void CSdlAppServ::SetParam(TInt aParam)
{
iReturnValue = aParam;
}
void CSdlAppServ::HandleObserverValue(TInt aService, TInt aReturnValue, TBool aMainThread)
{
if(iObserver != NULL && aMainThread)
{
switch(aService)
{
case MSDLObserver::EEventScreenSizeChanged:
if(aReturnValue == MSDLObserver::EScreenSizeChangedDefaultPalette)
EpocSdlEnv::LockPalette(EFalse);
break;
}
}
if(!aMainThread && aService == MSDLObserver::EEventSuspend)
{
if(iObserver == NULL ||
(gEpocEnv->iDsa->Stopped() && aReturnValue != MSDLObserver::ESuspendNoSuspend))
{
EpocSdlEnv::Suspend();
}
}
}
void CSdlAppServ::RunL()
{
if(iStatus == KErrNone)
{
switch(iService)
{
case CSdlAppServ::EAppSrvWaitDsa:
EpocSdlEnv::SetWaitDsa();
iReturnValue = EpocSdlEnv::IsDsaAvailable();
// }
// gEpocEnv->iDsa->Stop();
// gEpocEnv->iDsa->RestartL();
break;
case CSdlAppServ::EAppSrvStopThread:
gEpocEnv->iDsa->SetSuspend();
break;
case EpocSdlEnv::EDisableKeyBlocking:
EnvUtils::DisableKeyBlocking();
break;
case EAppSrvWindowPointerCursorMode:
iReturnValue = gEpocEnv->iDsa != NULL ?
gEpocEnv->iDsa->Session().PointerCursorMode() : KErrNotReady;
break;
case EAppSrvDsaStatus:
gEpocEnv->iDsa->Stop();
iReturnValue = KErrNone;
break;
case CDsa::ERequestUpdate:
gEpocEnv->iDsa->UnlockHWSurfaceRequestComplete();
break;
case EAppSrvNoop:
break;
case MSDLObserver::EEventResume:
case MSDLObserver::EEventSuspend:
case MSDLObserver::EEventScreenSizeChanged:
case MSDLObserver::EEventWindowReserved:
case MSDLObserver::EEventKeyMapInit:
case MSDLObserver::EEventWindowNotAvailable:
case MSDLObserver::EEventMainExit:
iReturnValue = ObserverEvent(iService, iReturnValue);
HandleObserverValue(iService, iReturnValue, ETrue);
break;
default:
PANIC(KErrNotSupported);
}
iStatus = KRequestPending;
iStatusPtr = &iStatus;
SetActive();
}
iSema.Signal();
}
void CSdlAppServ::DoCancel()
{
iSema.Wait();
TRequestStatus* s = &iStatus;
iAppThread.RequestComplete(s, KErrCancel);
}
MEventQueue& EpocSdlEnv::EventQueue()
{
__ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
return *gEpocEnv->iEventQueue;
}
TBool EpocSdlEnv::Flags(TInt aFlag)
{
const TInt flag = gEpocEnv->iEpocEnvFlags & aFlag;
return flag == aFlag;
}
TInt EpocSdlEnv::Argc()
{
__ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
return gEpocEnv->iArgc;
}
char** EpocSdlEnv::Argv()
{
__ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
return gEpocEnv->iArgv;
}
TBool EpocSdlEnv::IsDsaAvailable()
{
__ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
return gEpocEnv->iDsa != NULL && gEpocEnv->iDsa->IsDsaAvailable();
}
void EpocSdlEnv::WaitDsaAvailable()
{
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventWindowNotAvailable, 0);
gEpocEnv->iAppSrv->Request(CSdlAppServ::EAppSrvStopThread);
if(EpocSdlEnv::Flags(CSDL::EEnableFocusStop))
{
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventSuspend, 0);
}
}
void EpocSdlEnv::Suspend()
{
if(gEpocEnv->iDsa->Stopped() || EpocSdlEnv::Flags(CSDL::EEnableFocusStop))
{
// gEpocEnv->iDsa->ReleaseStop();
gEpocEnv->iDsa->SetSuspend();
RThread().Suspend();
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventResume, 0);
}
}
void EpocSdlEnv::SetWaitDsa()
{
if(!IsDsaAvailable())
{
RThread th;
th.Open(gEpocEnv->iId);
th.Suspend();
th.Close();
gEpocEnv->iDsa->SetSuspend();
}
}
void EpocSdlEnv::Resume()
{
gEpocEnv->iDsa->Resume();
RThread th;
th.Open(gEpocEnv->iId);
th.Resume();
th.Close();
const TInt value = gEpocEnv->iAppSrv->ObserverEvent(MSDLObserver::EEventResume, 0);
gEpocEnv->iAppSrv->HandleObserverValue(MSDLObserver::EEventResume, value, ETrue);
}
TInt EpocSdlEnv::AllocSwSurface(const TSize& aSize, TDisplayMode aMode)
{
return gEpocEnv->iDsa->AllocSurface(EFalse, aSize, aMode);
}
TInt EpocSdlEnv::AllocHwSurface(const TSize& aSize, TDisplayMode aMode)
{
return gEpocEnv->iDsa->AllocSurface(ETrue, aSize, aMode);
}
void EpocSdlEnv::UnlockHwSurface()
{
gEpocEnv->iDsa->UnlockHwSurface();
}
TUint8* EpocSdlEnv::LockHwSurface()
{
return gEpocEnv->iDsa->LockHwSurface();
}
void EpocSdlEnv::UpdateSwSurface()
{
gEpocEnv->iDsa->UpdateSwSurface();
}
TBool EpocSdlEnv::AddUpdateRect(TUint8* aAddress, const TRect& aUpdateRect, const TRect& aRect)
{
return gEpocEnv->iDsa->AddUpdateRect(aAddress, aUpdateRect, aRect);
}
void EpocSdlEnv::Request(TInt aService)
{
__ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
gEpocEnv->iAppSrv->Request(aService);
}
TSize EpocSdlEnv::WindowSize(const TSize& aRequestedSize)
{
__ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
if(EpocSdlEnv::Flags(CSDL::EAllowImageResize) && gEpocEnv->iDsa->WindowSize() != aRequestedSize)
{
TRAP_IGNORE(gEpocEnv->iDsa->CreateZoomerL(aRequestedSize));
}
return gEpocEnv->iDsa->WindowSize();
}
TSize EpocSdlEnv::WindowSize()
{
__ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
return gEpocEnv->iDsa->WindowSize();
}
TDisplayMode EpocSdlEnv::DisplayMode()
{
return gEpocEnv->iDsa->DisplayMode();
}
TPointerCursorMode EpocSdlEnv::PointerMode()
{
return static_cast<TPointerCursorMode>
(gEpocEnv->iAppSrv->RequestValue(CSdlAppServ::EAppSrvWindowPointerCursorMode));
}
TInt EpocSdlEnv::SetPalette(TInt aFirstcolor, TInt aColorCount, TUint32* aPalette)
{
return gEpocEnv->iDsa->SetPalette(aFirstcolor, aColorCount, aPalette);
}
void EpocSdlEnv::PanicMain(TInt aErr)
{
gEpocEnv->iAppSrv->PanicMain(aErr);
}
TInt EpocSdlEnv::AppendCleanupItem(const TSdlCleanupItem& aItem)
{
TRAPD(err, gEpocEnv->iCleanupItems->AppendL(aItem));
return err;
}
void EpocSdlEnv::RemoveCleanupItem(TAny* aItem)
{
for(TInt i = 0; i < gEpocEnv->iCleanupItems->Count(); i++)
{
if(gEpocEnv->iCleanupItems->At(i).iItem == aItem)
gEpocEnv->iCleanupItems->Delete(i);
}
}
void EpocSdlEnv::CleanupItems()
{
const TThreadId id = RThread().Id();
TInt last = gEpocEnv->iCleanupItems->Count() - 1;
TInt i;
for(i = last; i >= 0 ; i--)
{
TSdlCleanupItem& item = gEpocEnv->iCleanupItems->At(i);
if(item.iThread == id)
{
item.iThread = TThreadId(0);
item.iOperation(item.iItem);
}
}
last = gEpocEnv->iCleanupItems->Count() - 1;
for(i = last; i >= 0 ; i--)
{
TSdlCleanupItem& item = gEpocEnv->iCleanupItems->At(i);
if(item.iThread == TThreadId(0))
{
gEpocEnv->iCleanupItems->Delete(i);
}
}
}
void EpocSdlEnv::FreeSurface()
{
Request(CSdlAppServ::EAppSrvDsaStatus);
gEpocEnv->iDsa->Free();
}
void EpocSdlEnv::LockPalette(TBool aLock)
{
gEpocEnv->iDsa->LockPalette(aLock);
}
void EpocSdlEnv::ObserverEvent(TInt aService, TInt aParam)
{
const TBool sdlThread = RThread().Id() == gEpocEnv->iId;
const TInt valuea = gEpocEnv->iAppSrv->ObserverEvent(aService, aParam);
gEpocEnv->iAppSrv->HandleObserverValue(aService, valuea, !sdlThread);
if(sdlThread)
{
gEpocEnv->iAppSrv->SetParam(aParam);
const TInt valuet = gEpocEnv->iAppSrv->RequestValue(aService);
gEpocEnv->iAppSrv->HandleObserverValue(aService, valuet, EFalse);
}
}
TPoint EpocSdlEnv::WindowCoordinates(const TPoint& aPoint)
{
return gEpocEnv->iDsa->WindowCoordinates(aPoint);
}
void EpocSdlEnv::PanicMain(const TDesC& aInfo, TInt aErr)
{
gEpocEnv->iAppSrv->PanicMain(aInfo, aErr);
}
//Dsa is a low priority ao, it has to wait if its pending event, but ws
//event has been prioritized before it
//this is not called from app thread!
void EpocSdlEnv::WaitDeviceChange()
{
LockPalette(ETrue);
gEpocEnv->iAppSrv->RequestValue(CSdlAppServ::EAppSrvWaitDsa);
const TSize sz = WindowSize();
const TInt param = reinterpret_cast<TInt>(&sz);
ObserverEvent(MSDLObserver::EEventScreenSizeChanged, param);
// RThread().Suspend();
}
LOCAL_C TBool CheckSdl()
{
TInt isExit = ETrue;
RThread sdl;
if(sdl.Open(gEpocEnv->iId) == KErrNone)
{
if(sdl.ExitType() == EExitPending)
{
isExit = EFalse;
}
sdl.Close();
}
return isExit;
}
void EpocSdlEnvData::Free()
{
if(RThread().Id() == gEpocEnv->iId)
{
iDsa->Free();
return;
}
__ASSERT_ALWAYS(iArgv == NULL || CheckSdl(), PANIC(KErrNotReady));
for(TInt i = 0; i < iArgc; i++)
User::Free( iArgv[i] );
User::Free(iArgv);
delete iEventQueue;
if(iDsa != NULL)
iDsa->Free();
delete iDsa;
delete iAppSrv;
}
_LIT(KSDLMain, "SDLMain");
LOCAL_C int MainL()
{
gEpocEnv->iCleanupItems = new (ELeave) CArrayFixFlat<TSdlCleanupItem>(8);
char** envp=0;
/* !! process exits here if there is "exit()" in main! */
int ret = 0;
for(TInt i = 0; i < 6; i++)
{
void* f = (void*) gEpocEnv->iMain[i];
if(f != NULL)
{
switch(i)
{
case 0:
ret = ((mainfunc1)f)();
return ret;
case 3:
((mainfunc1)f)();
return ret;
case 1:
ret = ((mainfunc2)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv());
return ret;
case 4:
((mainfunc2)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv());
return ret;
case 2:
ret = ((mainfunc3)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv(), envp);
return ret;
case 5:
((mainfunc3)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv(), envp);
return ret;
}
}
}
PANIC(KErrNotFound);
return 0;
}
LOCAL_C TInt DoMain(TAny* /*aParam*/)
{
CTrapCleanup* cleanup = CTrapCleanup::New();
TBool fbsconnected = EFalse;
if(RFbsSession::GetSession() == NULL)
{
PANIC_IF_ERROR(RFbsSession::Connect());
fbsconnected = ETrue;
}
gEpocEnv->iAppSrv->Init();
#ifdef SYMBIANC
// Create stdlib
_REENT;
#endif
// Call stdlib main
int ret = 0;
//completes waiting rendesvous
RThread::Rendezvous(KErrNone);
TRAPD(err, err = MainL());
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventMainExit, err);
// Free resources and return
EpocSdlEnv::CleanupItems();
gEpocEnv->iCleanupItems->Reset();
delete gEpocEnv->iCleanupItems;
gEpocEnv->iCleanupItems = NULL;
gEpocEnv->Free(); //free up in thread resources
#ifdef SYMBIANC
_cleanup(); //this is normally called at exit, I call it here
#endif
if(fbsconnected)
RFbsSession::Disconnect();
#ifdef SYMBIANC
CloseSTDLIB();
#endif
// delete as;
delete cleanup;
return err == KErrNone ? ret : err;;
}
EXPORT_C CSDL::~CSDL()
{
gEpocEnv->Free();
User::Free(gEpocEnv);
gEpocEnv->iSdl = NULL;
}
EXPORT_C CSDL* CSDL::NewL(TInt aFlags)
{
__ASSERT_ALWAYS(gEpocEnv == NULL, PANIC(KErrAlreadyExists));
gEpocEnv = (EpocSdlEnvData*) User::AllocL(sizeof(EpocSdlEnvData));
Mem::FillZ(gEpocEnv, sizeof(EpocSdlEnvData));
gEpocEnv->iEpocEnvFlags = aFlags;
gEpocEnv->iEventQueue = CEventQueue::NewL();
gEpocEnv->iAppSrv = new (ELeave) CSdlAppServ();
gEpocEnv->iAppSrv->ConstructL();
CSDL* sdl = new (ELeave) CSDL();
gEpocEnv->iSdl = sdl;
return sdl;
}
/*
EXPORT_C void CSDL::ReInitL(TFlags aFlags)
{
const TFlags prevFlags = gEpocEnv->iEpocEnvFlags;
gEpocEnv->iEpocEnvFlags = aFlags;
TInt err = KErrNone;
if(((prevFlags & EDrawModeDSB) != (aFlags & EDrawModeDSB)) && gEpocEnv->iDsa)
{
delete gEpocEnv->iDsa;
gEpocEnv->iDsa = NULL;
gEpocEnv->iDsa = CDsa::RecreateL(EpocSdlEnv::Flags(CSDL::EDrawModeDSB));
}
}
*/
EXPORT_C void CSDL::SetContainerWindowL(RWindow& aWindow, RWsSession& aSession, CWsScreenDevice& aDevice)
{
if(gEpocEnv->iDsa == NULL)
gEpocEnv->iDsa = CDsa::CreateL(aSession);
gEpocEnv->iDsa->ConstructL(aWindow, aDevice);
}
EXPORT_C TThreadId CSDL::CallMainL(const TMainFunc& aFunc, TRequestStatus* const aStatus, const CDesC8Array* const aArg, TInt aFlags, TInt aStackSize)
{
ASSERT(gEpocEnv != NULL);
gEpocEnv->iMain = aFunc;
const TBool args = aArg != NULL;
gEpocEnv->iArgc = aArg->Count() + 1;
gEpocEnv->iArgv = (char**) User::AllocL(sizeof(char*) * (gEpocEnv->iArgc + 1));
TInt k = 0;
const TFileName processName = RProcess().FileName();
const TInt len = processName.Length();
gEpocEnv->iArgv[k] = (char*) User::AllocL(len + 1);
Mem::Copy(gEpocEnv->iArgv[k], processName.Ptr(), len);
gEpocEnv->iArgv[k][len] = 0;
for(TInt i = 0; args && (i < aArg->Count()); i++)
{
k++;
const TInt len = aArg->MdcaPoint(i).Length();
gEpocEnv->iArgv[k] = (char*) User::AllocL(len + 1);
Mem::Copy(gEpocEnv->iArgv[k], aArg->MdcaPoint(i).Ptr(), len);
gEpocEnv->iArgv[k][len] = 0;
}
gEpocEnv->iArgv[gEpocEnv->iArgc] = NULL;
RThread thread;
User::LeaveIfError(thread.Create(KSDLMain, DoMain, aStackSize, NULL, NULL));
if(aStatus != NULL)
{
thread.Logon(*aStatus);
}
gEpocEnv->iId = thread.Id();
thread.SetPriority(EPriorityLess);
if((aFlags & CSDL::ERequestResume) == 0)
{
thread.Resume();
}
thread.Close();
return gEpocEnv->iId;
}
EXPORT_C TInt CSDL::AppendWsEvent(const TWsEvent& aEvent)
{
return EpocSdlEnv::EventQueue().Append(aEvent);
}
EXPORT_C void CSDL::SDLPanic(const TDesC& aInfo, TInt aErr)
{
EpocSdlEnv::PanicMain(aInfo, aErr);
}
EXPORT_C TInt CSDL::GetSDLCode(TInt aScanCode)
{
if(aScanCode < 0)
return MAX_SCANCODE;
if(aScanCode >= MAX_SCANCODE)
return -1;
return KeyMap()[aScanCode];
}
EXPORT_C TInt CSDL::SDLCodesCount() const
{
return MAX_SCANCODE;
}
EXPORT_C void CSDL::ResetSDLCodes()
{
ResetKeyMap();
}
EXPORT_C void CSDL::SetOrientation(TOrientationMode aMode)
{
gEpocEnv->iDsa->SetOrientation(aMode);
}
EXPORT_C TInt CSDL::SetSDLCode(TInt aScanCode, TInt aSDLCode)
{
const TInt current = GetSDLCode(aScanCode);
if(aScanCode >= 0 && aScanCode < MAX_SCANCODE)
KeyMap()[aScanCode] = static_cast<SDLKey>(aSDLCode);
return current;
}
EXPORT_C MSDLObserver* CSDL::Observer()
{
return gEpocEnv->iAppSrv->Observer();
}
EXPORT_C void CSDL::SetObserver(MSDLObserver* aObserver)
{
gEpocEnv->iAppSrv->SetObserver(aObserver);
}
EXPORT_C void CSDL::Resume()
{
EpocSdlEnv::Resume();
}
EXPORT_C void CSDL::Suspend()
{
gEpocEnv->iDsa->DoStop();
}
EXPORT_C CSDL::CSDL()
{
}
EXPORT_C void CSDL::DisableKeyBlocking(CAknAppUi& aAppUi) const
{
gEpocEnv->iAppUi = &aAppUi;
EnvUtils::DisableKeyBlocking();
}
EXPORT_C TInt CSDL::SetBlitter(MBlitter* aBlitter)
{
if(gEpocEnv && gEpocEnv->iDsa)
{
gEpocEnv->iDsa->SetBlitter(aBlitter);
return KErrNone;
}
return KErrNotReady;
}
EXPORT_C TInt CSDL::AppendOverlay(MOverlay& aOverlay, TInt aPriority)
{
if(gEpocEnv && gEpocEnv->iDsa)
{
return gEpocEnv->iDsa->AppendOverlay(aOverlay, aPriority);
}
return KErrNotReady;
}
EXPORT_C TInt CSDL::RemoveOverlay(MOverlay& aOverlay)
{
if(gEpocEnv && gEpocEnv->iDsa)
{
return gEpocEnv->iDsa->RemoveOverlay(aOverlay);
}
return KErrNotReady;
}
EXPORT_C TInt CSDL::RedrawRequest()
{
if(gEpocEnv && gEpocEnv->iDsa)
{
return gEpocEnv->iDsa->RedrawRequest();
}
return KErrNotReady;
}
/*
EXPORT_C CSDL* CSDL::Current()
{
return gEpocEnv != NULL ? gEpocEnv->iSdl : NULL;
}
EXPORT_C TInt CSDL::SetVolume(TInt aVolume)
{
return EpocSdlEnv::SetVolume(aVolume);
}
EXPORT_C TInt CSDL::Volume() const
{
return EpocSdlEnv::Volume();
}
EXPORT_C TInt CSDL::MaxVolume() const
{
return EpocSdlEnv::MaxVolume();
}
*/
void EnvUtils::DisableKeyBlocking()
{
if(gEpocEnv->iAppUi != NULL)
return CCurrentAppUi::Cast(gEpocEnv->iAppUi)->DisableKeyBlocking();
}
TBool EnvUtils::Rendezvous(RThread& aThread, TRequestStatus& aStatus)
{
if(gEpocEnv->iId != TThreadId(0) &&
aThread.Open(gEpocEnv->iId) &&
aThread.ExitType() == EExitPending)
{
aThread.Rendezvous(aStatus);
return ETrue;
}
return EFalse;
}
// INCLUDES
#include <aknapp.h>
#include <aknappui.h>
#include <eikdoc.h>
#include <sdlepocapi.h>
#include <bautils.h>
#include <eikstart.h>
#include <badesca.h>
#include <bautils.h>
#include <apgcli.h>
#include <sdlmain.h>
#include <eikedwin.h>
#include <eiklabel.h>
#include <sdlexe.rsg>
#include <aknglobalmsgquery.h>
#include <apgwgnam.h>
// FORWARD DECLARATIONS
class CApaDocument;
//const TUid KSDLUID = { 0xF01F605E };
LOCAL_C void MakeCCmdLineL(const TDesC8& aParam, CDesC8Array& aArray)
{
const TChar dq('\"');
TLex8 lex(aParam);
TBool in = EFalse;
lex.SkipSpaceAndMark();
while(!lex.Eos())
{
TPtrC8 ptr;
if(in)
{
const TPtrC8 rem = lex.RemainderFromMark();
const TInt pos = rem.Locate(dq);
if(pos > 0)
{
lex.Inc(pos);
ptr.Set(lex.MarkedToken());
lex.SkipAndMark(1);
}
else
{
ptr.Set(rem);
}
in = EFalse;
}
else
{
ptr.Set(lex.NextToken());
const TInt pos = ptr.Locate(dq);
if(pos == 0)
{
lex.UnGetToMark();
lex.SkipAndMark(1);
in = ETrue;
continue; // back to in brace
}
else
lex.SkipSpaceAndMark();
}
aArray.AppendL(ptr);
}
}
NONSHARABLE_CLASS(TVirtualCursor) : public MOverlay
{
public:
TVirtualCursor();
void Set(const TRect& aRect, CFbsBitmap* aBmp, CFbsBitmap* aAlpha);
void Move(TInt aX, TInt aY);
void MakeEvent(TWsEvent& aEvent, const TPoint& aBasePos) const;
void Toggle();
TBool IsOn() const;
private:
void Draw(CBitmapContext& aGc, const TRect& aTargetRect, const TSize& aSize);
private:
TRect iRect;
TPoint iInc;
TPoint iPos;
TBool iIsOn;
CFbsBitmap* iCBmp;
CFbsBitmap* iAlpha;
};
TVirtualCursor::TVirtualCursor() : iInc(0, 0), iIsOn(EFalse), iCBmp(NULL)
{
}
const TInt KMaxMove = 10;
void TVirtualCursor::Move(TInt aX, TInt aY)
{
if(aX > 0 && iInc.iX > 0)
++iInc.iX;
else if(aX < 0 && iInc.iX < 0)
--iInc.iX;
else
iInc.iX = aX;
if(aY > 0 && iInc.iY > 0)
++iInc.iY;
else if(aY < 0 && iInc.iY < 0)
--iInc.iY;
else
iInc.iY = aY;
iInc.iX = Min(KMaxMove, iInc.iX);
iInc.iX = Max(-KMaxMove, iInc.iX);
iInc.iY = Min(KMaxMove, iInc.iY);
iInc.iY =Max(-KMaxMove, iInc.iY);
const TPoint pos = iPos + iInc;
if(iRect.Contains(pos))
{
iPos = pos;
}
else
{
iInc = TPoint(0, 0);
}
}
void TVirtualCursor::Toggle()
{
iIsOn = !iIsOn;
}
TBool TVirtualCursor::IsOn() const
{
return iIsOn;
}
void TVirtualCursor::Set(const TRect& aRect, CFbsBitmap* aBmp, CFbsBitmap* aAlpha)
{
iRect = aRect;
iCBmp = aBmp;
iAlpha = aAlpha;
}
void TVirtualCursor::MakeEvent(TWsEvent& aEvent, const TPoint& aBasePos) const
{
aEvent.SetType(EEventPointer),
aEvent.SetTimeNow();
TPointerEvent& pointer = *aEvent.Pointer();
pointer.iType = TPointerEvent::EButton1Down;
pointer.iPosition = iPos;
pointer.iParentPosition = aBasePos;
}
void TVirtualCursor::Draw(CBitmapContext& aGc, const TRect& /*aTargetRect*/, const TSize& /*aSize*/)
{
if(iIsOn && iCBmp != NULL)
{
const TRect rect(TPoint(0, 0), iCBmp->SizeInPixels());
aGc.AlphaBlendBitmaps(iPos, iCBmp, rect, iAlpha, TPoint(0, 0));
}
}
NONSHARABLE_CLASS(TSdlClass)
{
public:
TSdlClass();
void SetMain(const TMainFunc& aFunc, TInt aFlags, MSDLMainObs* aObs, TInt aExeFlags);
TInt SdlFlags() const;
const TMainFunc& Main() const;
void SendEvent(TInt aEvent, TInt aParam, CSDL* aSDL);
TInt AppFlags() const;
void AppFlags(TInt aFlags);
private:
TMainFunc iFunc;
TInt iSdlFlags;
TInt iExeFlags;
MSDLMainObs* iObs;
};
void TSdlClass::AppFlags(TInt aFlags)
{
iExeFlags |= aFlags;
}
void TSdlClass::SendEvent(TInt aEvent, TInt aParam, CSDL* aSDL)
{
if(iObs != NULL)
iObs->SDLMainEvent(aEvent, aParam, aSDL);
}
TInt TSdlClass::AppFlags() const
{
return iExeFlags;
}
void TSdlClass::SetMain(const TMainFunc& aFunc, TInt aFlags, MSDLMainObs* aObs, TInt aExeFlags)
{
iFunc = aFunc;
iSdlFlags = aFlags;
iExeFlags = aExeFlags;
iObs = aObs;
}
const TMainFunc& TSdlClass::Main() const
{
return iFunc;
}
TInt TSdlClass::SdlFlags() const
{
return iSdlFlags;
}
TSdlClass::TSdlClass()
{
Mem::FillZ(this, sizeof(this));
}
TSdlClass gSDLClass;
////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(CSDLApplication) : public CAknApplication
{
public:
CSDLApplication();
private:
CApaDocument* CreateDocumentL();
TFileName ResourceFileName() const;
TUid AppDllUid() const;
void FindMeL();
TUid iUid;
};
NONSHARABLE_CLASS(CSDLDocument) : public CEikDocument
{
public:
CSDLDocument(CEikApplication& aApp);
private:
CEikAppUi* CreateAppUiL();
};
////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(MExitWait)
{
public:
virtual void DoExit(TInt aErr) = 0;
};
/////////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(CExitWait) : public CActive
{
public:
CExitWait(MExitWait& aWait);
~CExitWait();
private:
void RunL();
void DoCancel();
private:
MExitWait& iWait;
TRequestStatus* iStatusPtr;
};
////////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(CSDLWin) : public CCoeControl
{
public:
void ConstructL(const TRect& aRect);
RWindow& GetWindow() const;
void SetNoDraw();
private:
void Draw(const TRect& aRect) const;
private:
TBool iNoDraw;
};
////////////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(CSDLAppUi) : public CAknAppUi, public MExitWait, MSDLObserver
{
public:
~CSDLAppUi();
private: // New functions
void ConstructL();
void HandleCommandL(TInt aCommand);
void HandleWsEventL(const TWsEvent& aEvent, CCoeControl* aDestination);
void HandleResourceChangeL(TInt aType);
void DoExit(TInt aErr);
TInt SdlEvent(TInt aEvent, TInt aParam);
TInt SdlThreadEvent(TInt aEvent, TInt aParam);
void StartL();
static TBool StartL(TAny* aThis);
TBool ParamEditorL(TDes& aCheat);
TBool ProcessCommandParametersL(CApaCommandLine &aCommandLine);
void PrepareToExit();
void HandleConsoleWindowL();
void HandleConsoleWindow();
void HandleForegroundEventL(TBool aForeground);
static TBool IdleRequestL(TAny* aThis);
TBool HandleKeyL(const TWsEvent& aEvent);
private:
CExitWait* iWait;
CSDLWin* iSDLWin;
CSDL* iSdl;
CIdle* iStarter;
TBool iExitRequest;
CDesC8Array* iParams;
TInt iResOffset;
CIdle* iIdle;
TInt iStdOut;
TVirtualCursor iCursor;
CFbsBitmap* iCBmp;
CFbsBitmap* iAlpha;
// TTime iLastPress;
// CSDL::TOrientationMode iOrientation;
};
////////////////////////////////////////////////////////////////////////////////////////7
CApaDocument* CSDLApplication::CreateDocumentL()
{
return new (ELeave) CSDLDocument(*this);
}
TUid CSDLApplication::AppDllUid() const
{
return iUid;
}
CSDLApplication::CSDLApplication()
{
TRAPD(err, FindMeL());
ASSERT(err == KErrNone);
}
void CSDLApplication::FindMeL()
{
RApaLsSession apa;
User::LeaveIfError(apa.Connect());
CleanupClosePushL(apa);
User::LeaveIfError(apa.GetAllApps());
TFileName name = RProcess().FileName();
TApaAppInfo info;
while(apa.GetNextApp(info) == KErrNone)
{
if(info.iFullName.CompareF(name) == 0)
{
iUid = info.iUid;
break;
}
}
CleanupStack::PopAndDestroy();
}
TFileName CSDLApplication::ResourceFileName() const
{
return KNullDesC();
}
///////////////////////////////////////////////////////////////////////////////////////////
CExitWait::CExitWait(MExitWait& aWait) : CActive(CActive::EPriorityStandard), iWait(aWait)
{
CActiveScheduler::Add(this);
SetActive();
iStatusPtr = &iStatus;
}
CExitWait::~CExitWait()
{
Cancel();
}
void CExitWait::RunL()
{
if(iStatusPtr != NULL )
iWait.DoExit(iStatus.Int());
}
void CExitWait::DoCancel()
{
if(iStatusPtr != NULL )
User::RequestComplete(iStatusPtr , KErrCancel);
}
//////////////////////////////////////////////////////////////////////////////////////////////
CSDLDocument::CSDLDocument(CEikApplication& aApp) : CEikDocument(aApp)
{}
CEikAppUi* CSDLDocument::CreateAppUiL()
{
return new (ELeave) CSDLAppUi;
}
///////////////////////////////////////////////////////////////////////////
void CSDLWin:: ConstructL(const TRect& aRect)
{
CreateWindowL();
SetRect(aRect);
ActivateL();
}
RWindow& CSDLWin::GetWindow() const
{
return Window();
}
void CSDLWin::Draw(const TRect& /*aRect*/) const
{
if(!iNoDraw)
{
CWindowGc& gc = SystemGc();
gc.SetPenStyle(CGraphicsContext::ESolidPen);
gc.SetPenColor(KRgbGray);
gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
gc.SetBrushColor(0xaaaaaa);
gc.DrawRect(Rect());
}
}
void CSDLWin::SetNoDraw()
{
iNoDraw = ETrue;
}
/////////////////////////////////////////////////////////////////////////
CSDLAppUi::~CSDLAppUi()
{
if(iIdle)
iIdle->Cancel();
delete iIdle;
if(iStarter != NULL)
iStarter->Cancel();
delete iStarter;
delete iWait;
delete iSdl;
delete iSDLWin;
delete iParams;
delete iCBmp;
delete iAlpha;
}
void CSDLAppUi::ConstructL()
{
BaseConstructL(ENoAppResourceFile | ENoScreenFurniture);
RLibrary lib;
User::LeaveIfError(lib.Load(_L("sdlexe.dll")));
TFileName name = lib.FileName();
lib.Close();
name.Replace(3, name.Length() - 3, _L("resource\\apps\\sdlexe.rsc"));
BaflUtils::NearestLanguageFile(iEikonEnv->FsSession(), name);
iResOffset = iCoeEnv->AddResourceFileL(name);
name.Replace(name.Length() - 3, 3, _L("mbm"));
TEntry e;
const TInt err = iEikonEnv->FsSession().Entry(name, e);
iCBmp = iEikonEnv->CreateBitmapL(name, 0);
iAlpha = iEikonEnv->CreateBitmapL(name, 1);
iIdle = CIdle::NewL(CActive::EPriorityIdle);
iSDLWin = new (ELeave) CSDLWin;
iSDLWin->ConstructL(ApplicationRect());
iSdl = CSDL::NewL(gSDLClass.SdlFlags());
gSDLClass.SendEvent(MSDLMainObs::ESDLCreated, 0, iSdl);
iSdl->SetObserver(this);
iSdl->DisableKeyBlocking(*this);
iSdl->SetContainerWindowL(
iSDLWin->GetWindow(),
iEikonEnv->WsSession(),
*iEikonEnv->ScreenDevice());
iSdl->AppendOverlay(iCursor, 0);
iCursor.Set(TRect(TPoint(0, 0), iSDLWin->Size()), iCBmp, iAlpha);
iStarter = CIdle::NewL(CActive::EPriorityLow);
iStarter->Start(TCallBack(StartL, this));
}
TBool CSDLAppUi::StartL(TAny* aThis)
{
static_cast<CSDLAppUi*>(aThis)->StartL();
return EFalse;
}
void CSDLAppUi::PrepareToExit()
{
CAknAppUiBase::PrepareToExit(); //aknappu::PrepareToExit crashes
iCoeEnv->DeleteResourceFile(iResOffset);
}
TBool CSDLAppUi::ProcessCommandParametersL(CApaCommandLine &aCommandLine)
{
const TPtrC8 cmdLine = aCommandLine.TailEnd();
iParams = new (ELeave) CDesC8ArrayFlat(8);
MakeCCmdLineL(cmdLine, *iParams);
return EFalse;
}
TBool CSDLAppUi::ParamEditorL(TDes& aCheat)
{
CAknTextQueryDialog* query = CAknTextQueryDialog::NewL(aCheat);
CleanupStack::PushL(query);
query->SetPromptL(_L("Enter parameters"));
CleanupStack::Pop();
return query->ExecuteLD(R_PARAMEDITOR);
}
void CSDLAppUi::StartL()
{
if(gSDLClass.AppFlags() & SDLEnv::EParamQuery)
{
TBuf8<256> cmd;
RFile file;
TInt err = file.Open(iEikonEnv->FsSession(), _L("sdl_param.txt"),EFileRead);
if(err == KErrNone)
{
file.Read(cmd);
file.Close();
MakeCCmdLineL(cmd, *iParams);
}
if(err != KErrNone || gSDLClass.AppFlags() & (SDLEnv::EParamQueryDialog ^ SDLEnv::EParamQuery))
{
TBuf<256> buffer;
if(ParamEditorL(buffer))
{
cmd.Copy(buffer);
MakeCCmdLineL(cmd, *iParams);
}
}
}
iWait = new (ELeave) CExitWait(*this);
iSdl->CallMainL(gSDLClass.Main(), &iWait->iStatus, iParams, CSDL::ENoParamFlags, 0xA000);
}
void CSDLAppUi::HandleCommandL(TInt aCommand)
{
switch(aCommand)
{
case EAknSoftkeyBack:
case EAknSoftkeyExit:
case EAknCmdExit:
case EEikCmdExit:
gSDLClass.AppFlags(SDLEnv::EAllowConsoleView);
if(iWait == NULL || !iWait->IsActive() || iSdl == NULL)
{
Exit();
}
else if(!iExitRequest)
{
iExitRequest = ETrue; //trick how SDL can be closed!
iSdl->Suspend();
}
break;
}
}
TBool CSDLAppUi::HandleKeyL(const TWsEvent& aEvent)
{
const TInt type = aEvent.Type();
if(!(type == EEventKey || type == EEventKeyUp || type == EEventKeyDown))
{
return ETrue;
}
const TKeyEvent& key = *aEvent.Key();
if((key.iScanCode == EStdKeyYes) && (gSDLClass.AppFlags() & SDLEnv::EVirtualMouse))
{
if(type == EEventKeyUp)
{
iCursor.Toggle();
iSdl->RedrawRequest();
}
return EFalse;
}
if(iCursor.IsOn())
{
switch(key.iScanCode)
{
case EStdKeyUpArrow:
iCursor.Move(0, -1);
break;
case EStdKeyDownArrow:
iCursor.Move(0, 1);
break;
case EStdKeyLeftArrow:
iCursor.Move(-1, 0);
break;
case EStdKeyRightArrow:
iCursor.Move(1, 0);
break;
case EStdKeyDevice3:
if(type == EEventKeyUp)
{
TWsEvent event;
iCursor.MakeEvent(event, iSDLWin->Position());
iSdl->AppendWsEvent(event);
}
return EFalse;
default:
return ETrue;
}
iSdl->RedrawRequest();
return EFalse;
}
return ETrue;
}
void CSDLAppUi::HandleWsEventL(const TWsEvent& aEvent, CCoeControl* aDestination)
{
if(iSdl && iWait && HandleKeyL(aEvent))
iSdl->AppendWsEvent(aEvent);
CAknAppUi::HandleWsEventL(aEvent, aDestination);
}
void CSDLAppUi::HandleResourceChangeL(TInt aType)
{
CAknAppUi::HandleResourceChangeL(aType);
if(aType == KEikDynamicLayoutVariantSwitch)
{
iSDLWin->SetRect(ApplicationRect());
iSdl->SetContainerWindowL(
iSDLWin->GetWindow(),
iEikonEnv->WsSession(),
*iEikonEnv->ScreenDevice());
}
}
void CSDLAppUi::DoExit(TInt/*Err*/)
{
iExitRequest = ETrue;
Exit();
}
TInt CSDLAppUi::SdlThreadEvent(TInt aEvent, TInt /*aParam*/)
{
switch(aEvent)
{
case MSDLObserver::EEventResume:
break;
case MSDLObserver::EEventSuspend:
if(iExitRequest)
return MSDLObserver::ESuspendNoSuspend;
break;
case MSDLObserver::EEventWindowReserved:
break;
case MSDLObserver::EEventWindowNotAvailable:
break;
case MSDLObserver::EEventScreenSizeChanged:
break;
}
return MSDLObserver::EParameterNone;
}
TInt CSDLAppUi::SdlEvent(TInt aEvent, TInt /*aParam*/)
{
switch(aEvent)
{
case MSDLObserver::EEventResume:
break;
case MSDLObserver::EEventSuspend:
if(iExitRequest)
return MSDLObserver::ESuspendNoSuspend;
break;
case MSDLObserver::EEventWindowReserved:
break;
case MSDLObserver::EEventWindowNotAvailable:
{
TRAP_IGNORE(HandleConsoleWindowL());
}
break;
case MSDLObserver::EEventScreenSizeChanged:
break;
case MSDLObserver::EEventKeyMapInit:
break;
case MSDLObserver::EEventMainExit:
if(iStdOut != 0)
{
gSDLClass.AppFlags(SDLEnv::EAllowConsoleView);
iEikonEnv->WsSession().SetWindowGroupOrdinalPosition(iStdOut, 0);
}
break;
}
return MSDLObserver::EParameterNone;
}
void CSDLAppUi::HandleForegroundEventL(TBool aForeground)
{
CAknAppUi::HandleForegroundEventL(aForeground);
if(!aForeground)
HandleConsoleWindow();
}
void CSDLAppUi::HandleConsoleWindow()
{
if(!iIdle->IsActive())
iIdle->Start(TCallBack(IdleRequestL, this));
}
TBool CSDLAppUi::IdleRequestL(TAny* aThis)
{
static_cast<CSDLAppUi*>(aThis)->HandleConsoleWindowL();
return EFalse;
}
void CSDLAppUi::HandleConsoleWindowL()
{
if(gSDLClass.AppFlags() & SDLEnv::EAllowConsoleView)
{
return;
}
RWsSession& ses = iEikonEnv->WsSession();
const TInt focus = ses.GetFocusWindowGroup();
CApaWindowGroupName* name = CApaWindowGroupName::NewLC(ses, focus);
const TPtrC caption = name->Caption();
if(0 == caption.CompareF(_L("STDOUT")))
{
iStdOut = focus;
ses.SetWindowGroupOrdinalPosition(iEikonEnv->RootWin().Identifier(), 0);
}
CleanupStack::PopAndDestroy(); //name
}
////////////////////////////////////////////////////////////////////////
CApaApplication* NewApplication()
{
return new CSDLApplication();
}
EXPORT_C TInt SDLEnv::SetMain(const TMainFunc& aFunc, TInt aSdlFlags, MSDLMainObs* aObs, TInt aSdlExeFlags)
{
gSDLClass.SetMain(aFunc, aSdlFlags, aObs, aSdlExeFlags);
return EikStart::RunApplication(NewApplication);
}
//////////////////////////////////////////////////////////////////////
TInt SDLUiPrint(const TDesC8& /*aInfo*/)
{
return KErrNotFound;
}
#include<eikstart.h>
#include<sdlmain.h>
#include<sdlepocapi.h>
GLREF_C TInt E32Main()
{
return SDLEnv::SetMain(SDL_main, CSDL::EEnableFocusStop | CSDL::EAllowImageResize,
NULL, SDLEnv::EParamQuery | SDLEnv::EVirtualMouse);
}
\ No newline at end of file
/*
vectorbuffer.cpp
yet another circle buffer
Markus Mertama
*/
#include"vectorbuffer.h"
void VectorPanic(TInt aErr, TInt aLine)
{
TBuf<64> b;
b.Format(_L("vector buffer at % d "), aLine);
User::Panic(b, aErr);
}
void TNodeBuffer::TNode::Terminator(TNodeBuffer::TNode* aNode)
{
Mem::Copy(iSucc, &aNode, sizeof(TNode*));
}
TInt TNodeBuffer::TNode::Size() const
{
return reinterpret_cast<const TUint8*>(iSucc) - Ptr();
}
const TUint8* TNodeBuffer::TNode::Ptr() const
{
return reinterpret_cast<const TUint8*>(this) + sizeof(TNode);
}
TNodeBuffer::TNode* TNodeBuffer::TNode::Empty(TUint8* aBuffer)
{
TNode* node = reinterpret_cast<TNode*>(aBuffer);
node->iSucc = node + 1;
return node;
}
TNodeBuffer::TNode* TNodeBuffer::TNode::New(TNode* aPred, const TDesC8& aData)
{
TNode* node = aPred->Size() == 0 ? aPred : aPred->iSucc;
TUint8* start = reinterpret_cast<TUint8*>(node) + sizeof(TNode);
node->iSucc = reinterpret_cast<TNode*>(start + aData.Size());
node->iSucc->iSucc = NULL; //terminator
__ASSERT_DEBUG(node->Size() == aData.Size(), VECPANIC(KErrCorrupt));
Mem::Copy(start, aData.Ptr(), aData.Size());
return node;
}
\ No newline at end of file
/*
vectorbuffer.cpp
yet another circle buffer
Markus Mertama
*/
#ifndef __VECTORBUFFER_H__
#define __VECTORBUFFER_H__
#include<e32std.h>
#define VLOG(x)
#define VECPANIC(x) VectorPanic(x, __LINE__)
void VectorPanic(TInt, TInt);
//int DEBUG_INT;
NONSHARABLE_CLASS(TNodeBuffer)
{
public:
protected:
NONSHARABLE_CLASS(TNode)
{
public:
static TNode* Empty(TUint8* iBuffer);
static TNode* New(TNode* aPrev, const TDesC8& aData);
const TUint8* Ptr() const;
TInt Size() const;
inline TNode* Succ();
static void SetSucc(TNode*& aNode);
void Terminator(TNode* aNode);
private:
TNode* iSucc;
};
};
inline TNodeBuffer::TNode* TNodeBuffer::TNode::Succ()
{
return iSucc;
}
template <TInt C>
NONSHARABLE_CLASS(TVectorBuffer) : public TNodeBuffer
{
public:
TVectorBuffer();
TInt Append(const TDesC8& aData);
// TInt AppendOverwrite(const TDesC8& aData);
TPtrC8 Shift();
TPtrC8 operator[](TInt aIndex) const;
TInt Size() const;
private:
TInt GetRoom(TInt aSize) const;
TInt Unreserved() const;
private:
TNode* iTop;
TNode* iBottom;
TInt iSize;
TUint8 iBuffer[C];
};
template <TInt C>
TVectorBuffer<C>::TVectorBuffer() : iSize(0)
{
Mem::FillZ(iBuffer, C);
iTop = TNode::Empty(iBuffer); //these points to buffer
iBottom = TNode::Empty(iBuffer);
}
template<TInt C >
TInt TVectorBuffer<C>::Unreserved() const
{
__ASSERT_DEBUG(iBottom < iBottom->Succ(), VECPANIC(KErrCorrupt));
const TInt bytesbetween =
reinterpret_cast<const TUint8*>(iBottom->Succ()) -
reinterpret_cast<const TUint8*>(iTop);
const TInt topsize = sizeof(TNode);
if(bytesbetween > 0) //bytesbetween is room between bottom and top
{ //therefore free room is subracted from free space
const TInt room = C - bytesbetween - topsize;
return room;
}
if(bytesbetween == 0)
{
if(Size() > 0)
return 0;
else
return C - topsize;
}
const TInt room = -bytesbetween - topsize; //free is space between pointers
return room;
}
template <TInt C>
TInt TVectorBuffer<C>::GetRoom(TInt aSize) const
{
const TInt bytesnew = sizeof(TNode) + aSize;
const TInt room = Unreserved() - bytesnew;
return room;
}
template <TInt C>
TInt TVectorBuffer<C>::Append(const TDesC8& aData) //ei ole ok!
{
const TInt len = aData.Length();
if(GetRoom(len) < 0)
{
return KErrOverflow;
}
if(iBottom->Succ()->Ptr() - iBuffer > (C - (len + TInt(sizeof(TNode)))))
{
VLOG("rc");
// RDebug::Print(_L("vector: append"));
TNode* p = TNode::Empty(iBuffer);
iBottom->Terminator(p);
iBottom = p;
return Append(aData);
// Append();
// iBottom = TNode::New(p, aData); //just append something into end
}
//DEBUG_INT++;
iBottom = TNode::New(iBottom, aData);
iSize += len;
return KErrNone;
}
/*
template <TInt C>
TInt TVectorBuffer<C>::AppendOverwrite(const TDesC8& aData) //ei ole ok!
{
while(Append(aData) == KErrOverflow)
{
if(iTop->Succ() == NULL)
{
return KErrUnderflow;
}
//Shift(); //data is lost
}
return KErrNone;
}
*/
template <TInt C>
TPtrC8 TVectorBuffer<C>::Shift()
{
__ASSERT_ALWAYS(iTop->Succ() != NULL, VECPANIC(KErrUnderflow)); //can never pass-by bottom
TNode* node = iTop;
iTop = iTop->Succ();
if(iTop > node)
{
// DEBUG_INT--;
iSize -= node->Size();
return TPtrC8(node->Ptr(), node->Size());
}
else
{
// RDebug::Print(_L("vector: shift"));
return Shift(); //this happens when buffer is terminated, and data lies in next
}
}
template <TInt C>
TInt TVectorBuffer<C>::Size() const
{
return iSize;
}
template <TInt C>
TPtrC8 TVectorBuffer<C>::operator[](TInt aIndex) const
{
TInt index = 0;
TNode* t = iTop->Size() > 0 ? iTop : iTop->Succ(); //eliminate terminator
while(index < aIndex)
{
TNode* nt = t->Succ();
if(nt < t)
{
nt = nt->Succ();
}
t = nt;
if(t->Size() > 0)
index++;
__ASSERT_ALWAYS(t->Succ() != NULL, VECPANIC(KErrUnderflow)); //can never pass-by bottom
}
return t->Ptr();
}
template <class T, TInt C>
NONSHARABLE_CLASS(TVector) : public TVectorBuffer<C * sizeof(T)>
{
public:
TVector();
TInt Append(const T& aData);
const T& Shift();
TInt Size() const;
const T& operator[](TInt aIndex) const;
};
template <class T, TInt C>
TVector<T, C>::TVector() : TVectorBuffer<C * sizeof(T)>()
{
}
template <class T, TInt C>
TInt TVector<T, C>::Append(const T& aData)
{
const TPckgC<T> data(aData);
return TVectorBuffer<C * sizeof(T)>::Append(data);
}
template <class T, TInt C>
const T& TVector<T, C>::Shift()
{
const TPtrC8 ptr = TVectorBuffer<C * sizeof(T)>::Shift();
return *(reinterpret_cast<const T*>(ptr.Ptr()));
}
template <class T, TInt C>
TInt TVector<T, C>::Size() const
{
return TVectorBuffer<C * sizeof(T)>::Size() / sizeof(T);
}
template <class T, TInt C>
const T& TVector<T, C>::operator[](TInt aIndex) const
{
const TPtrC8 ptr = TVectorBuffer<C * sizeof(T)>::operator[](aIndex);
return *(reinterpret_cast<const T*>(ptr.Ptr()));
}
#endif
......@@ -25,7 +25,7 @@
#ifndef HAVE_GETENV
#if defined(__WIN32__) && !defined(_WIN32_WCE)
#if defined(__WIN32__) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
......
......@@ -31,8 +31,6 @@
#include "beos/SDL_systhread_c.h"
#elif SDL_THREAD_DC
#include "dc/SDL_systhread_c.h"
#elif SDL_THREAD_EPOC
#include "epoc/SDL_systhread_c.h"
#elif SDL_THREAD_OS2
#include "os2/SDL_systhread_c.h"
#elif SDL_THREAD_PTH
......@@ -43,6 +41,8 @@
#include "irix/SDL_systhread_c.h"
#elif SDL_THREAD_WIN32
#include "win32/SDL_systhread_c.h"
#elif SDL_THREAD_SYMBIAN
#include "symbian/SDL_systhread_c.h"
#else
#error Need thread implementation for this platform
#include "generic/SDL_systhread_c.h"
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_sysmutex.cpp
Epoc version by Markus Mertama (w@iki.fi)
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_sysmutex.c,v 1.1.2.3 2000/06/22 15:25:23 hercules Exp $";
#endif
/* Mutex functions using the Win32 API */
//#include <stdio.h>
//#include <stdlib.h>
#include <e32std.h>
#include "epoc_sdl.h"
#include "SDL_error.h"
#include "SDL_mutex.h"
#ifdef EKA2 //???
struct SDL_mutex
{
TInt handle;
};
#else
struct _SDL_mutex
{
TInt handle;
};
#endif
extern TInt CreateUnique(TInt (*aFunc)(const TDesC& aName, TAny*, TAny*), TAny*, TAny*);
TInt NewMutex(const TDesC& aName, TAny* aPtr1, TAny*)
{
return ((RMutex*)aPtr1)->CreateGlobal(aName);
}
void DeleteMutex(TAny* aMutex)
{
SDL_DestroyMutex ((SDL_mutex*) aMutex);
}
/* Create a mutex */
SDL_mutex *SDL_CreateMutex(void)
{
RMutex rmutex;
TInt status = CreateUnique(NewMutex, &rmutex, NULL);
if(status != KErrNone)
{
SDL_SetError("Couldn't create mutex");
}
SDL_mutex* mutex = new /*(ELeave)*/ SDL_mutex;
mutex->handle = rmutex.Handle();
EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem(DeleteMutex, mutex));
return(mutex);
}
/* Free the mutex */
void SDL_DestroyMutex(SDL_mutex *mutex)
{
if ( mutex )
{
RMutex rmutex;
rmutex.SetHandle(mutex->handle);
if(rmutex.IsHeld())
{
rmutex.Signal();
}
rmutex.Close();
EpocSdlEnv::RemoveCleanupItem(mutex);
delete(mutex);
mutex = NULL;
}
}
/* Lock the mutex */
int SDL_mutexP(SDL_mutex *mutex)
{
if ( mutex == NULL ) {
SDL_SetError("Passed a NULL mutex");
return -1;
}
RMutex rmutex;
rmutex.SetHandle(mutex->handle);
rmutex.Wait();
return(0);
}
/* Unlock the mutex */
int SDL_mutexV(SDL_mutex *mutex)
{
if ( mutex == NULL ) {
SDL_SetError("Passed a NULL mutex");
return -1;
}
RMutex rmutex;
rmutex.SetHandle(mutex->handle);
rmutex.Signal();
return(0);
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_syssem.cpp
Epoc version by Markus Mertama (w@iki.fi)
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_syssem.c,v 1.1.2.4 2000/06/22 15:24:48 hercules Exp $";
#endif
/* Semaphore functions using the Win32 API */
//#include <stdio.h>
//#include <stdlib.h>
#include <e32std.h>
#include "SDL_error.h"
#include "SDL_thread.h"
#define SDL_MUTEX_TIMEOUT -2
struct SDL_semaphore
{
TInt handle;
TInt count;
};
extern TInt CreateUnique(TInt (*aFunc)(const TDesC& aName, TAny*, TAny*), TAny*, TAny*);
#ifndef EKA2
extern TInt NewThread(const TDesC& aName, TAny* aPtr1, TAny* aPtr2);
#endif
TInt NewSema(const TDesC& aName, TAny* aPtr1, TAny* aPtr2)
{
TInt value = *((TInt*) aPtr2);
return ((RSemaphore*)aPtr1)->CreateGlobal(aName, value);
}
/* Create a semaphore */
SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
{
RSemaphore s;
TInt status = CreateUnique(NewSema, &s, &initial_value);
if(status != KErrNone)
{
SDL_SetError("Couldn't create semaphore");
}
SDL_semaphore* sem = new /*(ELeave)*/ SDL_semaphore;
sem->handle = s.Handle();
sem->count = initial_value;
return(sem);
}
/* Free the semaphore */
void SDL_DestroySemaphore(SDL_sem *sem)
{
if ( sem )
{
RSemaphore sema;
sema.SetHandle(sem->handle);
while(--sem->count)
sema.Signal();
sema.Close();
delete sem;
sem = NULL;
}
}
#ifndef EKA2
struct TInfo
{
TInfo(TInt aTime, TInt aHandle) :
iTime(aTime), iHandle(aHandle), iVal(0) {}
TInt iTime;
TInt iHandle;
TInt iVal;
};
TBool ThreadRun(TAny* aInfo)
{
TInfo* info = STATIC_CAST(TInfo*, aInfo);
User::After(info->iTime);
RSemaphore sema;
sema.SetHandle(info->iHandle);
sema.Signal();
info->iVal = SDL_MUTEX_TIMEOUT;
return 0;
}
#endif
void _WaitAll(SDL_sem *sem)
{
//since SemTryWait may changed the counter.
//this may not be atomic, but hopes it works.
RSemaphore sema;
sema.SetHandle(sem->handle);
sema.Wait();
while(sem->count < 0)
{
sema.Wait();
}
}
int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
{
if ( ! sem ) {
SDL_SetError("Passed a NULL sem");
return -1;
}
if ( timeout == SDL_MUTEX_MAXWAIT )
{
_WaitAll(sem);
return SDL_MUTEX_MAXWAIT;
}
#ifdef EKA2
RSemaphore sema;
sema.SetHandle(sem->handle);
if(KErrNone == sema.Wait(timeout))
return 0;
return -1;
#else
RThread thread;
TInfo* info = new (ELeave)TInfo(timeout, sem->handle);
TInt status = CreateUnique(NewThread, &thread, info);
if(status != KErrNone)
return status;
thread.Resume();
_WaitAll(sem);
if(thread.ExitType() == EExitPending)
{
thread.Kill(SDL_MUTEX_TIMEOUT);
}
thread.Close();
return info->iVal;
#endif
}
int SDL_SemTryWait(SDL_sem *sem)
{
if(sem->count > 0)
{
sem->count--;
}
return SDL_MUTEX_TIMEOUT;
}
int SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
Uint32 SDL_SemValue(SDL_sem *sem)
{
if ( ! sem ) {
SDL_SetError("Passed a NULL sem");
return 0;
}
return sem->count;
}
int SDL_SemPost(SDL_sem *sem)
{
if ( ! sem ) {
SDL_SetError("Passed a NULL sem");
return -1;
}
sem->count++;
RSemaphore sema;
sema.SetHandle(sem->handle);
sema.Signal();
return 0;
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_systhread.cpp
Epoc thread management routines for SDL
Epoc version by Markus Mertama (w@iki.fi)
*/
#include "epoc_sdl.h"
//#include <stdlib.h>
//#include <stdio.h>
extern "C" {
#undef NULL
#include "SDL_error.h"
#include "SDL_thread.h"
#include "SDL_systhread.h"
#include "SDL_thread_c.h"
}
#include <e32std.h>
#include "epoc_sdl.h"
static int object_count;
int RunThread(TAny* data)
{
CTrapCleanup* cleanup = CTrapCleanup::New();
TRAPD(err, SDL_RunThread(data));
EpocSdlEnv::CleanupItems();
delete cleanup;
return(err);
}
TInt NewThread(const TDesC& aName, TAny* aPtr1, TAny* aPtr2)
{
return ((RThread*)(aPtr1))->Create(aName,
RunThread,
KDefaultStackSize,
NULL,
aPtr2);
}
int CreateUnique(TInt (*aFunc)(const TDesC& aName, TAny*, TAny*), TAny* aPtr1, TAny* aPtr2)
{
TBuf<16> name;
TInt status = KErrNone;
do
{
object_count++;
name.Format(_L("SDL_%x"), object_count);
status = aFunc(name, aPtr1, aPtr2);
}
while(status == KErrAlreadyExists);
return status;
}
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args)
{
RThread rthread;
const TInt status = CreateUnique(NewThread, &rthread, args);
if (status != KErrNone)
{
delete(((RThread*)(thread->handle)));
thread->handle = NULL;
SDL_SetError("Not enough resources to create thread");
return(-1);
}
rthread.Resume();
thread->handle = rthread.Handle();
return(0);
}
void SDL_SYS_SetupThread(void)
{
return;
}
Uint32 SDL_ThreadID(void)
{
RThread current;
const TThreadId id = current.Id();
return id;
}
void SDL_SYS_WaitThread(SDL_Thread *thread)
{
SDL_TRACE1("Close thread", thread);
RThread t;
const TInt err = t.Open(thread->threadid);
if(err == KErrNone && t.ExitType() == EExitPending)
{
TRequestStatus status;
t.Logon(status);
User::WaitForRequest(status);
}
t.Close();
/* RUndertaker taker;
taker.Create();
TRequestStatus status;
taker.Logon(status, thread->handle);
User::WaitForRequest(status);
taker.Close();*/
SDL_TRACE1("Closed thread", thread);
}
/* WARNING: This function is really a last resort.
* Threads should be signaled and then exit by themselves.
* TerminateThread() doesn't perform stack and DLL cleanup.
*/
void SDL_SYS_KillThread(SDL_Thread *thread)
{
RThread rthread;
rthread.SetHandle(thread->handle);
rthread.Kill(0);
rthread.Close();
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_systhread_c.h
Epoc version by Markus Mertama (w@iki.fi)
*/
typedef int SYS_ThreadHandle;
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_systimer.cpp
Epoc version by Hannu Viitala (hannu.j.viitala@mbnet.fi)
Markus Mertama
*/
#include <e32std.h>
#include <e32hal.h>
extern "C" {
#include "SDL_error.h"
#include "SDL_thread.h"
#include "SDL_timer.h"
#include "SDL_timer_c.h"
static TUint start = 0;
static TInt tickPeriodMilliSeconds;
void SDL_StartTicks(void)
{
/* Set first ticks value */
start = User::TickCount();
TTimeIntervalMicroSeconds32 period;
TInt tmp = UserHal::TickPeriod(period);
tickPeriodMilliSeconds = period.Int() / 1000;
}
Uint32 SDL_GetTicks(void)
{
TUint deltaTics = User::TickCount() - start;
return(deltaTics * tickPeriodMilliSeconds);
}
void SDL_Delay(Uint32 ms)
{
User::After(TTimeIntervalMicroSeconds32(ms*1000));
}
/* Data to handle a single periodic alarm */
static int timer_alive = 0;
static SDL_Thread *timer = NULL;
static int RunTimer(void *unused)
{
while ( timer_alive )
{
if (SDL_timer_running)
{
SDL_ThreadedTimerCheck();
}
SDL_Delay(10);
}
return(0);
}
/* This is only called if the event thread is not running */
int SDL_SYS_TimerInit(void)
{
if(timer != NULL)
return (-1);
timer_alive = 1;
timer = SDL_CreateThread(RunTimer, NULL);
if ( timer == NULL )
return(-1);
return(SDL_SetTimerThreaded(1));
}
void SDL_SYS_TimerQuit(void)
{
timer_alive = 0;
if ( timer )
{
SDL_WaitThread(timer, NULL);
timer = NULL;
}
}
int SDL_SYS_StartTimer(void)
{
SDL_SetError("Internal logic error: Epoc uses threaded timer");
return(-1);
}
void SDL_SYS_StopTimer(void)
{
return;
}
} // extern "C"
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_epocevents.cpp
Handle the event stream, converting Epoc events into SDL events
Epoc version by Hannu Viitala (hannu.j.viitala@mbnet.fi)
*/
#include <stdio.h>
#undef NULL
extern "C" {
//#define DEBUG_TRACE_ENABLED
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_keysym.h"
#include "SDL_keyboard.h"
#include "SDL_events_c.h"
#include "SDL_timer.h"
}; /* extern "C" */
#include "SDL_epocvideo.h"
#include "SDL_epocevents_c.h"
#include<linereader.h>
#include<bautils.h>
#include <hal.h>
extern "C" {
/* The translation tables from a console scancode to a SDL keysym */
static SDLKey keymap[MAX_SCANCODE];
static SDL_keysym *TranslateKey(_THIS, int scancode, SDL_keysym *keysym);
void DisableKeyBlocking(_THIS);
}; /* extern "C" */
TBool isCursorVisible = EFalse;
int EPOC_HandleWsEvent(_THIS, const TWsEvent& aWsEvent)
{
int posted = 0;
SDL_keysym keysym;
// SDL_TRACE1("hws %d", aWsEvent.Type());
switch (aWsEvent.Type())
{
case EEventPointer: /* Mouse pointer events */
{
const TPointerCursorMode mode = Private->EPOC_WsSession.PointerCursorMode();
if(mode == EPointerCursorNone)
{
return 0; //TODO: Find out why events are get despite of cursor should be off
}
const TPointerEvent* pointerEvent = aWsEvent.Pointer();
TPoint mousePos = pointerEvent->iPosition;
/*!! TODO Pointer do not yet work properly
//SDL_TRACE1("SDL: EPOC_HandleWsEvent, pointerEvent->iType=%d", pointerEvent->iType); //!!
if (Private->EPOC_ShrinkedHeight) {
mousePos.iY <<= 1; // Scale y coordinate to shrinked screen height
}
if (Private->EPOC_ShrinkedWidth) {
mousePos.iX <<= 1; // Scale x coordinate to shrinked screen width
}
*/
posted += SDL_PrivateMouseMotion(0, 0, mousePos.iX, mousePos.iY); /* Absolute position on screen */
switch (pointerEvent->iType)
{
case TPointerEvent::EButton1Down:
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, 0, 0);
break;
case TPointerEvent::EButton1Up:
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, 0, 0);
break;
case TPointerEvent::EButton2Down:
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_RIGHT, 0, 0);
break;
case TPointerEvent::EButton2Up:
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_RIGHT, 0, 0);
break;
case TPointerEvent::EButton3Down:
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_MIDDLE, 0, 0);
break;
case TPointerEvent::EButton3Up:
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_MIDDLE, 0, 0);
break;
} // switch
break;
}
case EEventKeyDown: /* Key events */
{
#ifdef SYMBIAN_CRYSTAL
// special case: 9300/9500 rocker down, simulate left mouse button
if (aWsEvent.Key()->iScanCode == EStdKeyDeviceA)
{
const TPointerCursorMode mode = Private->EPOC_WsSession.PointerCursorMode();
if(mode != EPointerCursorNone)
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, 0, 0);
}
#endif
(void*)TranslateKey(_this, aWsEvent.Key()->iScanCode, &keysym);
#ifndef DISABLE_JOYSTICK
/* Special handling */
switch((int)keysym.sym) {
case SDLK_CAPSLOCK:
if (!isCursorVisible) {
/* Enable virtual cursor */
HAL::Set(HAL::EMouseState, HAL::EMouseState_Visible);
}
else {
/* Disable virtual cursor */
HAL::Set(HAL::EMouseState, HAL::EMouseState_Invisible);
}
isCursorVisible = !isCursorVisible;
break;
}
#endif
posted += SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
break;
}
case EEventKeyUp: /* Key events */
{
#ifdef SYMBIAN_CRYSTAL
// special case: 9300/9500 rocker up, simulate left mouse button
if (aWsEvent.Key()->iScanCode == EStdKeyDeviceA)
{
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, 0, 0);
}
#endif
posted += SDL_PrivateKeyboard(SDL_RELEASED, TranslateKey(_this, aWsEvent.Key()->iScanCode, &keysym));
break;
}
case EEventFocusGained: /* SDL window got focus */
{
Private->EPOC_IsWindowFocused = ETrue;
posted += SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS);
/* Draw window background and screen buffer */
DisableKeyBlocking(_this); //Markus: guess why:-)
RedrawWindowL(_this);
break;
}
case EEventFocusLost: /* SDL window lost focus */
{
/*
CFbsBitmap* bmp = new (ELeave) CFbsBitmap();
bmp->Create(Private->EPOC_ScreenSize, Private->EPOC_DisplayMode);
Private->EPOC_WsScreen->CopyScreenToBitmap(bmp);
Private->EPOC_WindowGc->Activate(Private->EPOC_WsWindow);
Private->EPOC_WsWindow.BeginRedraw(TRect(Private->EPOC_WsWindow.Size()));
Private->EPOC_WindowGc->BitBlt(TPoint(0, 0), bmp);
Private->EPOC_WsWindow.EndRedraw();
Private->EPOC_WindowGc->Deactivate();
bmp->Save(_L("C:\\scr.mbm"));
delete bmp;
*/
Private->EPOC_IsWindowFocused = EFalse;
posted += SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS);
RWsSession s;
s.Connect();
RWindowGroup g(s);
g.Construct(TUint32(&g), EFalse);
g.EnableReceiptOfFocus(EFalse);
RWindow w(s);
w.Construct(g, TUint32(&w));
w.SetExtent(TPoint(0, 0), Private->EPOC_WsWindow.Size());
w.SetOrdinalPosition(0);
w.Activate();
w.Close();
g.Close();
s.Close();
/*
Private->EPOC_WsSession.SetWindowGroupOrdinalPosition(Private->EPOC_WsWindowGroupID, -1);
SDL_Delay(500);
TInt focus = -1;
while(focus < 0)
{
const TInt curr = Private->EPOC_WsSession.GetFocusWindowGroup();
if(curr != Private->EPOC_WsWindowGroupID)
focus = curr;
else
SDL_Delay(500);
}
if(1 < Private->EPOC_WsSession.GetWindowGroupOrdinalPriority(Private->EPOC_WsWindowGroupID))
{
Private->EPOC_WsSession.SetWindowGroupOrdinalPosition(focus, -1);
SDL_Delay(500);
Private->EPOC_WsSession.SetWindowGroupOrdinalPosition(focus, 0);
}
*/
/*//and the request redraw
TRawEvent redrawEvent;
redrawEvent.Set(TRawEvent::ERedraw);
Private->EPOC_WsSession.SimulateRawEvent(redrawEvent);
Private->EPOC_WsSession.Flush();*/
#if 0
//!! Not used
// Wait and eat events until focus is gained again
while (ETrue) {
Private->EPOC_WsSession.EventReady(&Private->EPOC_WsEventStatus);
User::WaitForRequest(Private->EPOC_WsEventStatus);
Private->EPOC_WsSession.GetEvent(Private->EPOC_WsEvent);
TInt eventType = Private->EPOC_WsEvent.Type();
Private->EPOC_WsEventStatus = KRequestPending;
//Private->EPOC_WsSession.EventReady(&Private->EPOC_WsEventStatus);
if (eventType == EEventFocusGained) {
RedrawWindowL(_this);
break;
}
}
#endif
break;
}
case EEventModifiersChanged:
{
TModifiersChangedEvent* modEvent = aWsEvent.ModifiersChanged();
TUint modstate = KMOD_NONE;
if (modEvent->iModifiers == EModifierLeftShift)
modstate |= KMOD_LSHIFT;
if (modEvent->iModifiers == EModifierRightShift)
modstate |= KMOD_RSHIFT;
if (modEvent->iModifiers == EModifierLeftCtrl)
modstate |= KMOD_LCTRL;
if (modEvent->iModifiers == EModifierRightCtrl)
modstate |= KMOD_RCTRL;
if (modEvent->iModifiers == EModifierLeftAlt)
modstate |= KMOD_LALT;
if (modEvent->iModifiers == EModifierRightAlt)
modstate |= KMOD_RALT;
if (modEvent->iModifiers == EModifierLeftFunc)
modstate |= KMOD_LMETA;
if (modEvent->iModifiers == EModifierRightFunc)
modstate |= KMOD_RMETA;
if (modEvent->iModifiers == EModifierCapsLock)
modstate |= KMOD_CAPS;
SDL_SetModState(STATIC_CAST(SDLMod,(modstate | KMOD_LSHIFT)));
break;
}
default:
break;
}
return posted;
}
extern "C" {
void EPOC_PumpEvents(_THIS)
{
int posted = 0; // !! Do we need this?
//Private->EPOC_WsSession.EventReady(&Private->EPOC_WsEventStatus);
while (Private->EPOC_WsEventStatus != KRequestPending) {
Private->EPOC_WsSession.GetEvent(Private->EPOC_WsEvent);
posted = EPOC_HandleWsEvent(_this, Private->EPOC_WsEvent);
Private->EPOC_WsEventStatus = KRequestPending;
Private->EPOC_WsSession.EventReady(&Private->EPOC_WsEventStatus);
}
}
_LIT(KMapFileName, "C:\\sdl_info\\sdlkeymap.cfg");
LOCAL_C void ReadL(RFs& aFs, RArray<TInt>& aArray)
{
TInt drive = -1;
TFileName name(KMapFileName);
for(TInt i = 'z'; drive < 0 && i >= 'a'; i--)
{
name[0] = (TUint16)i;
if(BaflUtils::FileExists(aFs, name))
drive = i;
}
if(drive < 0)
return;
CLineReader* reader = CLineReader::NewLC(aFs, name);
while(reader->NextL())
{
TPtrC ln = reader->Current();
TLex line(ln);
TInt n = 0;
for(;;)
{
const TPtrC token = line.NextToken();
if(token.Length() == 0)
break;
if((n & 1) != 0)
{
TInt value;
TLex lex(token);
User::LeaveIfError(lex.Val(value));
User::LeaveIfError(aArray.Append(value));
}
n++;
}
}
CleanupStack::PopAndDestroy();
}
void EPOC_InitOSKeymap(_THIS)
{
int i;
/* Initialize the key translation table */
for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
keymap[i] = SDLK_UNKNOWN;
/* Numbers */
for ( i = 0; i<32; ++i ){
keymap[' ' + i] = (SDLKey)(SDLK_SPACE+i);
}
/* e.g. Alphabet keys */
for ( i = 0; i<32; ++i ){
keymap['A' + i] = (SDLKey)(SDLK_a+i);
}
keymap[EStdKeyBackspace] = SDLK_BACKSPACE;
keymap[EStdKeyTab] = SDLK_TAB;
keymap[EStdKeyEnter] = SDLK_RETURN;
keymap[EStdKeyEscape] = SDLK_ESCAPE;
keymap[EStdKeySpace] = SDLK_SPACE;
keymap[EStdKeyPause] = SDLK_PAUSE;
keymap[EStdKeyHome] = SDLK_HOME;
keymap[EStdKeyEnd] = SDLK_END;
keymap[EStdKeyPageUp] = SDLK_PAGEUP;
keymap[EStdKeyPageDown] = SDLK_PAGEDOWN;
keymap[EStdKeyDelete] = SDLK_DELETE;
keymap[EStdKeyUpArrow] = SDLK_UP;
keymap[EStdKeyDownArrow] = SDLK_DOWN;
keymap[EStdKeyLeftArrow] = SDLK_LEFT;
keymap[EStdKeyRightArrow] = SDLK_RIGHT;
keymap[EStdKeyCapsLock] = SDLK_CAPSLOCK;
keymap[EStdKeyLeftShift] = SDLK_LSHIFT;
keymap[EStdKeyRightShift] = SDLK_RSHIFT;
keymap[EStdKeyLeftAlt] = SDLK_LALT;
keymap[EStdKeyRightAlt] = SDLK_RALT;
keymap[EStdKeyLeftCtrl] = SDLK_LCTRL;
keymap[EStdKeyRightCtrl] = SDLK_RCTRL;
keymap[EStdKeyLeftFunc] = SDLK_LMETA;
keymap[EStdKeyRightFunc] = SDLK_RMETA;
keymap[EStdKeyInsert] = SDLK_INSERT;
keymap[EStdKeyComma] = SDLK_COMMA;
keymap[EStdKeyFullStop] = SDLK_PERIOD;
keymap[EStdKeyForwardSlash] = SDLK_SLASH;
keymap[EStdKeyBackSlash] = SDLK_BACKSLASH;
keymap[EStdKeySemiColon] = SDLK_SEMICOLON;
keymap[EStdKeySingleQuote] = SDLK_QUOTE;
keymap[EStdKeyHash] = SDLK_HASH;
keymap[EStdKeySquareBracketLeft] = SDLK_LEFTBRACKET;
keymap[EStdKeySquareBracketRight] = SDLK_RIGHTBRACKET;
keymap[EStdKeyMinus] = SDLK_MINUS;
keymap[EStdKeyEquals] = SDLK_EQUALS;
keymap[EStdKeyF1] = SDLK_F1; /* chr + q */
keymap[EStdKeyF2] = SDLK_F2; /* chr + w */
keymap[EStdKeyF3] = SDLK_F3; /* chr + e */
keymap[EStdKeyF4] = SDLK_F4; /* chr + r */
keymap[EStdKeyF5] = SDLK_F5; /* chr + t */
keymap[EStdKeyF6] = SDLK_F6; /* chr + y */
keymap[EStdKeyF7] = SDLK_F7; /* chr + i */
keymap[EStdKeyF8] = SDLK_F8; /* chr + o */
keymap[EStdKeyF9] = SDLK_F9; /* chr + a */
keymap[EStdKeyF10] = SDLK_F10; /* chr + s */
keymap[EStdKeyF11] = SDLK_F11; /* chr + d */
keymap[EStdKeyF12] = SDLK_F12; /* chr + f */
#ifndef SYMBIAN_CRYSTAL
//!!7650 additions
#ifdef __WINS__
keymap[EStdKeyXXX] = SDLK_RETURN; /* "fire" key */
#else
keymap[EStdKeyDevice3] = SDLK_RETURN; /* "fire" key */
#endif
keymap[EStdKeyNkpAsterisk] = SDLK_ASTERISK;
keymap[EStdKeyYes] = SDLK_HOME; /* "call" key */
keymap[EStdKeyNo] = SDLK_END; /* "end call" key */
keymap[EStdKeyDevice0] = SDLK_SPACE; /* right menu key */
keymap[EStdKeyDevice1] = SDLK_ESCAPE; /* left menu key */
keymap[EStdKeyDevice2] = SDLK_POWER; /* power key */
#endif
#ifdef SYMBIAN_CRYSTAL
keymap[EStdKeyMenu] = SDLK_ESCAPE; // menu key
keymap[EStdKeyDevice6] = SDLK_LEFT; // Rocker (joystick) left
keymap[EStdKeyDevice7] = SDLK_RIGHT; // Rocker (joystick) right
keymap[EStdKeyDevice8] = SDLK_UP; // Rocker (joystick) up
keymap[EStdKeyDevice9] = SDLK_DOWN; // Rocker (joystick) down
keymap[EStdKeyLeftFunc] = SDLK_LALT; //chr?
keymap[EStdKeyRightFunc] = SDLK_RALT;
keymap[EStdKeyDeviceA] = SDLK_RETURN; /* "fire" key */
#endif
///////////////////////////////////////////////////////////
RFs fs;
if(KErrNone == fs.Connect())
{
RArray<TInt> array;
TRAPD(err, ReadL(fs, array));
if(err == KErrNone && array.Count() > 0)
{
SDLKey temp[MAX_SCANCODE];
Mem::Copy(temp, keymap, MAX_SCANCODE * sizeof(SDLKey));
for(TInt k = 0; k < array.Count(); k+= 2)
{
const TInt oldval = array[k];
const TInt newval = array[k + 1];
if(oldval >= 0 && oldval < MAX_SCANCODE && newval >= 0 && newval < MAX_SCANCODE)
{
keymap[oldval] = temp[newval];
}
}
}
array.Close();
}
fs.Close();
///////////////////////////////////////////////////////////
/* !!TODO
EStdKeyNumLock=0x1b,
EStdKeyScrollLock=0x1c,
EStdKeyNkpForwardSlash=0x84,
EStdKeyNkpAsterisk=0x85,
EStdKeyNkpMinus=0x86,
EStdKeyNkpPlus=0x87,
EStdKeyNkpEnter=0x88,
EStdKeyNkp1=0x89,
EStdKeyNkp2=0x8a,
EStdKeyNkp3=0x8b,
EStdKeyNkp4=0x8c,
EStdKeyNkp5=0x8d,
EStdKeyNkp6=0x8e,
EStdKeyNkp7=0x8f,
EStdKeyNkp8=0x90,
EStdKeyNkp9=0x91,
EStdKeyNkp0=0x92,
EStdKeyNkpFullStop=0x93,
EStdKeyMenu=0x94,
EStdKeyBacklightOn=0x95,
EStdKeyBacklightOff=0x96,
EStdKeyBacklightToggle=0x97,
EStdKeyIncContrast=0x98,
EStdKeyDecContrast=0x99,
EStdKeySliderDown=0x9a,
EStdKeySliderUp=0x9b,
EStdKeyDictaphonePlay=0x9c,
EStdKeyDictaphoneStop=0x9d,
EStdKeyDictaphoneRecord=0x9e,
EStdKeyHelp=0x9f,
EStdKeyOff=0xa0,
EStdKeyDial=0xa1,
EStdKeyIncVolume=0xa2,
EStdKeyDecVolume=0xa3,
EStdKeyDevice0=0xa4,
EStdKeyDevice1=0xa5,
EStdKeyDevice2=0xa6,
EStdKeyDevice3=0xa7,
EStdKeyDevice4=0xa8,
EStdKeyDevice5=0xa9,
EStdKeyDevice6=0xaa,
EStdKeyDevice7=0xab,
EStdKeyDevice8=0xac,
EStdKeyDevice9=0xad,
EStdKeyDeviceA=0xae,
EStdKeyDeviceB=0xaf,
EStdKeyDeviceC=0xb0,
EStdKeyDeviceD=0xb1,
EStdKeyDeviceE=0xb2,
EStdKeyDeviceF=0xb3,
EStdKeyApplication0=0xb4,
EStdKeyApplication1=0xb5,
EStdKeyApplication2=0xb6,
EStdKeyApplication3=0xb7,
EStdKeyApplication4=0xb8,
EStdKeyApplication5=0xb9,
EStdKeyApplication6=0xba,
EStdKeyApplication7=0xbb,
EStdKeyApplication8=0xbc,
EStdKeyApplication9=0xbd,
EStdKeyApplicationA=0xbe,
EStdKeyApplicationB=0xbf,
EStdKeyApplicationC=0xc0,
EStdKeyApplicationD=0xc1,
EStdKeyApplicationE=0xc2,
EStdKeyApplicationF=0xc3,
EStdKeyYes=0xc4,
EStdKeyNo=0xc5,
EStdKeyIncBrightness=0xc6,
EStdKeyDecBrightness=0xc7,
EStdKeyCaseOpen=0xc8,
EStdKeyCaseClose=0xc9
*/
}
static SDL_keysym *TranslateKey(_THIS, int scancode, SDL_keysym *keysym)
{
// char debug[256];
//SDL_TRACE1("SDL: TranslateKey, scancode=%d", scancode); //!!
/* Set the keysym information */
keysym->scancode = scancode;
if ((scancode >= MAX_SCANCODE) &&
((scancode - ENonCharacterKeyBase + 0x0081) >= MAX_SCANCODE)) {
SDL_SetError("Too big scancode");
keysym->scancode = SDLK_UNKNOWN;
keysym->mod = KMOD_NONE;
return keysym;
}
keysym->mod = SDL_GetModState();
/* Handle function keys: F1, F2, F3 ... */
if (keysym->mod & KMOD_META) {
if (scancode >= 'A' && scancode < ('A' + 24)) { /* first 32 alphabet keys */
switch(scancode) {
case 'Q': scancode = EStdKeyF1; break;
case 'W': scancode = EStdKeyF2; break;
case 'E': scancode = EStdKeyF3; break;
case 'R': scancode = EStdKeyF4; break;
case 'T': scancode = EStdKeyF5; break;
case 'Y': scancode = EStdKeyF6; break;
case 'U': scancode = EStdKeyF7; break;
case 'I': scancode = EStdKeyF8; break;
case 'A': scancode = EStdKeyF9; break;
case 'S': scancode = EStdKeyF10; break;
case 'D': scancode = EStdKeyF11; break;
case 'F': scancode = EStdKeyF12; break;
}
keysym->sym = keymap[scancode];
}
}
if (scancode >= ENonCharacterKeyBase) {
// Non character keys
keysym->sym = keymap[scancode -
ENonCharacterKeyBase + 0x0081]; // !!hard coded
} else {
keysym->sym = keymap[scancode];
}
/* Remap the arrow keys if the device is rotated */
if (Private->EPOC_ScreenOrientation == CFbsBitGc::EGraphicsOrientationRotated270) {
switch(keysym->sym) {
case SDLK_UP: keysym->sym = SDLK_LEFT; break;
case SDLK_DOWN: keysym->sym = SDLK_RIGHT; break;
case SDLK_LEFT: keysym->sym = SDLK_DOWN; break;
case SDLK_RIGHT:keysym->sym = SDLK_UP; break;
}
}
/* If UNICODE is on, get the UNICODE value for the key */
keysym->unicode = 0;
#if 0 // !!TODO:unicode
if ( SDL_TranslateUNICODE )
{
/* Populate the unicode field with the ASCII value */
keysym->unicode = scancode;
}
#endif
//!!
//sprintf(debug, "SDL: TranslateKey: keysym->scancode=%d, keysym->sym=%d, keysym->mod=%d",
// keysym->scancode, keysym->sym, keysym->mod);
//SDL_TRACE(debug); //!!
return(keysym);
}
}; /* extern "C" */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_epocvideo.cpp
Epoc based SDL video driver implementation
Thanks to Peter van Sebille, the author of EMame. It is a great example of
low level graphics coding in Epoc.
Epoc version by Hannu Viitala (hannu.j.viitala@mbnet.fi)
Assembler routines by Kimmo Kinnunen
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern "C" {
#include "SDL_error.h"
#include "SDL_timer.h"
#include "SDL_video.h"
#undef NULL
#include "SDL_pixels_c.h"
#include "SDL.h"
};
#include "SDL_epocvideo.h"
#include "SDL_epocevents_c.h"
#include "sdl_epocruntime.h"
#include <hal.h>
#include <coedef.h>
#include <flogger.h>
#ifdef SYMBIAN_QUARTZ
SDL_VideoDevice* _thisDevice;
#endif
_LIT(KLibName, "SDL");
/* For debugging */
//if old SOS, from 7.x this is public!
class CLockable : public CFbsBitmap
{
public:
static CLockable* Lockable(CFbsBitmap* aBmp) {return static_cast<CLockable*>(aBmp);}
void Lock() {LockHeap();}
void Unlock() {UnlockHeap();}
};
#define LockHeap(x) CLockable::Lockable(x)->Lock()
#define UnlockHeap(x) CLockable::Lockable(x)->Unlock()
void RDebug_Print_b(char* error_str, void* param)
{
TBuf8<128> error8((TUint8*)error_str);
TBuf<128> error;
error.Copy(error8);
#ifndef TRACE_TO_FILE
if (param) //!! Do not work if the parameter is really 0!!
RDebug::Print(error, param);
else
RDebug::Print(error);
#else
if (param) //!! Do not work if the parameter is really 0!!
RFileLogger::WriteFormat(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error, param);
else
RFileLogger::Write(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error);
#endif
}
extern "C" void RDebug_Print(char* error_str, void* param)
{
RDebug_Print_b(error_str, param);
}
int Debug_AvailMem2()
{
//User::CompressAllHeaps();
TMemoryInfoV1Buf membuf;
User::LeaveIfError(UserHal::MemoryInfo(membuf));
TMemoryInfoV1 minfo = membuf();
return(minfo.iFreeRamInBytes);
}
extern "C" int Debug_AvailMem()
{
return(Debug_AvailMem2());
}
extern "C" {
/* Initialization/Query functions */
static int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat);
static SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
static SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
static int EPOC_SetColors(_THIS, int firstcolor, int ncolors,
SDL_Color *colors);
static void EPOC_VideoQuit(_THIS);
/* Hardware surface functions */
static int EPOC_AllocHWSurface(_THIS, SDL_Surface *surface);
static int EPOC_LockHWSurface(_THIS, SDL_Surface *surface);
static int EPOC_FlipHWSurface(_THIS, SDL_Surface *surface);
static void EPOC_UnlockHWSurface(_THIS, SDL_Surface *surface);
static void EPOC_FreeHWSurface(_THIS, SDL_Surface *surface);
static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
static int EPOC_Available(void);
static SDL_VideoDevice *EPOC_CreateDevice(int devindex);
void DrawBackground(_THIS);
void DirectDraw(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
void DirectDrawRotated(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
/* Mouse functions */
static WMcursor *EPOC_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y);
static void EPOC_FreeWMCursor(_THIS, WMcursor *cursor);
static int EPOC_ShowWMCursor(_THIS, WMcursor *cursor);
/* !!For 12 bit screen HW. Table for fast conversion from 8 bit to 12 bit */
// TUint16 is enough, but using TUint32 so we can use better instruction selection on ARMI
static TUint32 EPOC_HWPalette_256_to_Screen[256];
VideoBootStrap EPOC_bootstrap = {
"epoc", "EPOC system",
EPOC_Available, EPOC_CreateDevice
};
const TUint32 WindowClientHandle = 9210; //!! const
/* Epoc video driver bootstrap functions */
static int EPOC_Available(void)
{
return 1; /* Always available */
}
static void EPOC_DeleteDevice(SDL_VideoDevice *device)
{
free(device->hidden);
free(device);
}
static SDL_VideoDevice *EPOC_CreateDevice(int /*devindex*/)
{
SDL_VideoDevice *device;
SDL_TRACE("SDL:EPOC_CreateDevice");
/* Allocate all variables that we free on delete */
device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
if ( device ) {
memset(device, 0, (sizeof *device));
device->hidden = (struct SDL_PrivateVideoData *)
malloc((sizeof *device->hidden));
}
if ( (device == NULL) || (device->hidden == NULL) ) {
SDL_OutOfMemory();
if ( device ) {
free(device);
}
return(0);
}
memset(device->hidden, 0, (sizeof *device->hidden));
/* Set the function pointers */
device->VideoInit = EPOC_VideoInit;
device->ListModes = EPOC_ListModes;
device->SetVideoMode = EPOC_SetVideoMode;
device->SetColors = EPOC_SetColors;
device->UpdateRects = NULL;
device->VideoQuit = EPOC_VideoQuit;
device->AllocHWSurface = EPOC_AllocHWSurface;
device->CheckHWBlit = NULL;
device->FillHWRect = NULL;
device->SetHWColorKey = NULL;
device->SetHWAlpha = NULL;
device->LockHWSurface = EPOC_LockHWSurface;
device->UnlockHWSurface = EPOC_UnlockHWSurface;
device->FlipHWSurface = EPOC_FlipHWSurface;
device->FreeHWSurface = EPOC_FreeHWSurface;
device->SetIcon = NULL;
device->SetCaption = NULL;
device->GetWMInfo = NULL;
device->FreeWMCursor = EPOC_FreeWMCursor;
device->CreateWMCursor = EPOC_CreateWMCursor;
device->ShowWMCursor = EPOC_ShowWMCursor;
device->WarpWMCursor = NULL;
device->InitOSKeymap = EPOC_InitOSKeymap;
device->PumpEvents = EPOC_PumpEvents;
device->free = EPOC_DeleteDevice;
return device;
}
int GetBpp(TDisplayMode displaymode)
{
/*TInt numColors = TDisplayModeUtils::NumDisplayModeColors(displaymode);
TInt bitsPerPixel = 1;
for (TInt32 i = 2; i < numColors; i <<= 1, bitsPerPixel++);
return bitsPerPixel;*/
return TDisplayModeUtils::NumDisplayModeBitsPerPixel(displaymode);
}
void DisableKeyBlocking(_THIS)
{
// Disable key blocking
TRawEvent event;
event.Set((TRawEvent::TType)/*EDisableKeyBlock*/51); // !!EDisableKeyBlock not found in epoc32\include!
Private->EPOC_WsSession.SimulateRawEvent(event);
}
void ConstructWindowL(_THIS)
{
TInt error;
SDL_TRACE("SDL:ConstructWindowL");
error = Private->EPOC_WsSession.Connect();
User::LeaveIfError(error);
Private->EPOC_WsScreen=new(ELeave) CWsScreenDevice(Private->EPOC_WsSession);
User::LeaveIfError(Private->EPOC_WsScreen->Construct());
User::LeaveIfError(Private->EPOC_WsScreen->CreateContext(Private->EPOC_WindowGc));
Private->EPOC_WsWindowGroup=RWindowGroup(Private->EPOC_WsSession);
User::LeaveIfError(Private->EPOC_WsWindowGroup.Construct(WindowClientHandle));
Private->EPOC_WsWindowGroup.SetOrdinalPosition(0);
// Set window group name (the same as process name)) !!Gives always "EPOC" in WINS
RProcess thisProcess;
TParse exeName;
exeName.Set(thisProcess.FileName(), NULL, NULL);
TBuf<32> winGroupName;
winGroupName.Append(0);
winGroupName.Append(0);
winGroupName.Append(0);// uid
winGroupName.Append(0);
winGroupName.Append(exeName.Name()); // caption
winGroupName.Append(0);
winGroupName.Append(0); //doc name
Private->EPOC_WsWindowGroup.SetName(winGroupName);
Private->EPOC_WsWindow=RWindow(Private->EPOC_WsSession);
// Markus, it was:
// User::LeaveIfError(Private->EPOC_WsWindow.Construct(Private->EPOC_WsWindowGroup,WindowClientHandle ));
// but SOS 7.0s debug does not accept same window handle twice
User::LeaveIfError(Private->EPOC_WsWindow.Construct(Private->EPOC_WsWindowGroup,WindowClientHandle - 1));
Private->EPOC_WsWindow.SetBackgroundColor(KRgbWhite);
Private->EPOC_WsWindow.Activate();
Private->EPOC_WsWindow.SetSize(Private->EPOC_WsScreen->SizeInPixels());
Private->EPOC_WsWindow.SetVisible(ETrue);
Private->EPOC_WsWindowGroupID = Private->EPOC_WsWindowGroup.Identifier();
Private->EPOC_IsWindowFocused = EFalse;
DisableKeyBlocking(_this); //disable key blocking
}
int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat)
{
// !!TODO:handle leave functions!
int i;
SDL_TRACE("SDL:EPOC_VideoInit");
/* Initialize all variables that we clean on shutdown */
for ( i=0; i<SDL_NUMMODES; ++i ) {
Private->SDL_modelist[i] = (SDL_Rect *)malloc(sizeof(SDL_Rect));
Private->SDL_modelist[i]->x = Private->SDL_modelist[i]->y = 0;
}
/* Modes sorted largest to smallest */
Private->SDL_modelist[0]->w = 800; Private->SDL_modelist[0]->h = 250;
Private->SDL_modelist[1]->w = 640; Private->SDL_modelist[1]->h = 480;
Private->SDL_modelist[2]->w = 480; Private->SDL_modelist[2]->h = 600;
Private->SDL_modelist[3]->w = 640; Private->SDL_modelist[3]->h = 400;
Private->SDL_modelist[4]->w = 352; Private->SDL_modelist[4]->h = 416;
Private->SDL_modelist[5]->w = 416; Private->SDL_modelist[5]->h = 352;
Private->SDL_modelist[6]->w = 416; Private->SDL_modelist[6]->h = 312;
Private->SDL_modelist[7]->w = 352; Private->SDL_modelist[7]->h = 264;
Private->SDL_modelist[8]->w = 800; Private->SDL_modelist[8]->h = 240; //for doom all these..
Private->SDL_modelist[9]->w = 640; Private->SDL_modelist[9]->h = 240;
Private->SDL_modelist[10]->w = 480; Private->SDL_modelist[10]->h = 240;
Private->SDL_modelist[11]->w = 640; Private->SDL_modelist[11]->h = 240;
Private->SDL_modelist[12]->w = 352; Private->SDL_modelist[12]->h = 240;
Private->SDL_modelist[13]->w = 416; Private->SDL_modelist[13]->h = 240;
Private->SDL_modelist[14]->w = 416; Private->SDL_modelist[14]->h = 240;
Private->SDL_modelist[15]->w = 352; Private->SDL_modelist[15]->h = 240;
Private->SDL_modelist[16]->w = 640; Private->SDL_modelist[16]->h = 200;
Private->SDL_modelist[17]->w = 320; Private->SDL_modelist[17]->h = 240; //...for doom, currently engine renders no-higher windows :-(, propably should get fixed
Private->SDL_modelist[18]->w = 320; Private->SDL_modelist[18]->h = 200;
Private->SDL_modelist[19]->w = 256; Private->SDL_modelist[19]->h = 192;
Private->SDL_modelist[20]->w = 176; Private->SDL_modelist[20]->h = 208;
Private->SDL_modelist[21]->w = 208; Private->SDL_modelist[21]->h = 176; // Rotated
Private->SDL_modelist[22]->w = 160; Private->SDL_modelist[22]->h = 144;
Private->SDL_modelist[23]->w = 640; Private->SDL_modelist[2]->h = 200; //s80 some new modes
Private->SDL_modelist[24]->w = 640; Private->SDL_modelist[2]->h = 320; //s90 modes are added
Private->SDL_modelist[25]->w = 640; Private->SDL_modelist[2]->h = 240; //here
Private->SDL_modelist[26]->w = 640; Private->SDL_modelist[4]->h = 200; //now
Private->SDL_modelist[27] = NULL;
/* Construct Epoc window */
ConstructWindowL(_this);
/* Initialise Epoc frame buffer */
TDisplayMode displayMode = Private->EPOC_WsScreen->DisplayMode();
#if !defined(__WINS__) && !defined(TEST_BM_DRAW)
TScreenInfoV01 screenInfo;
TPckg<TScreenInfoV01> sInfo(screenInfo);
UserSvr::ScreenInfo(sInfo);
Private->EPOC_ScreenSize = screenInfo.iScreenSize;
Private->EPOC_DisplayMode = displayMode;
Private->EPOC_HasFrameBuffer = screenInfo.iScreenAddressValid;
Private->EPOC_FrameBuffer = Private->EPOC_HasFrameBuffer ? (TUint8*) screenInfo.iScreenAddress : NULL;
Private->EPOC_BytesPerPixel = ((GetBpp(displayMode)-1) / 8) + 1;
Private->EPOC_BytesPerScanLine = screenInfo.iScreenSize.iWidth * Private->EPOC_BytesPerPixel;
Private->EPOC_BytesPerScreen = Private->EPOC_BytesPerScanLine * Private->EPOC_ScreenSize.iHeight;
SDL_TRACE1("Screen width %d", screenInfo.iScreenSize.iWidth);
SDL_TRACE1("Screen height %d", screenInfo.iScreenSize.iHeight);
SDL_TRACE1("Screen dmode %d", displayMode);
SDL_TRACE1("Screen valid %d", screenInfo.iScreenAddressValid);
SDL_TRACE1("bpp %d", Private->EPOC_BytesPerPixel);
SDL_TRACE1("bpsl %d", Private->EPOC_BytesPerScanLine);
SDL_TRACE1("bps %d", Private->EPOC_BytesPerScreen);
/* It seems that in SA1100 machines for 8bpp displays there is a 512 palette table at the
* beginning of the frame buffer. E.g. Series 7 and Netbook.
* In 12 bpp machines the table has 16 entries.
*/
if (Private->EPOC_HasFrameBuffer && GetBpp(displayMode) == 8)
{
Private->EPOC_FrameBuffer += 512;
}
else
{
Private->EPOC_FrameBuffer += 32;
}
/*if (Private->EPOC_HasFrameBuffer && GetBpp(displayMode) == 12)
Private->EPOC_FrameBuffer += 16 * 2;
if (Private->EPOC_HasFrameBuffer && GetBpp(displayMode) == 16)
Private->EPOC_FrameBuffer += 16 * 2;
*/
#else /* defined __WINS__ */
/* Create bitmap, device and context for screen drawing */
Private->EPOC_ScreenSize = Private->EPOC_WsScreen->SizeInPixels();
Private->EPOC_Bitmap = new (ELeave) CWsBitmap(Private->EPOC_WsSession);
Private->EPOC_Bitmap->Create(Private->EPOC_ScreenSize, displayMode);
Private->EPOC_DisplayMode = displayMode;
Private->EPOC_HasFrameBuffer = ETrue;
Private->EPOC_FrameBuffer = NULL; /* Private->EPOC_Bitmap->DataAddress() can change any time */
Private->EPOC_BytesPerPixel = ((GetBpp(displayMode)-1) / 8) + 1;
Private->EPOC_BytesPerScanLine = Private->EPOC_WsScreen->SizeInPixels().iWidth * Private->EPOC_BytesPerPixel;
#endif /* __WINS__ */
#ifndef SYMBIAN_CRYSTAL
// Get draw device for updating the screen
TScreenInfoV01 screenInfo2;
Epoc_Runtime::GetScreenInfo(screenInfo2);
TRAPD(status, Private->EPOC_DrawDevice = CFbsDrawDevice::NewScreenDeviceL(screenInfo2, displayMode));
User::LeaveIfError(status);
#endif
/* The "best" video format should be returned to caller. */
vformat->BitsPerPixel = /*!!GetBpp(displayMode) */ 8;
vformat->BytesPerPixel = /*!!Private->EPOC_BytesPerPixel*/ 1;
/* Activate events for me */
Private->EPOC_WsEventStatus = KRequestPending;
Private->EPOC_WsSession.EventReady(&Private->EPOC_WsEventStatus);
SDL_TRACE("SDL:WsEventStatus");
User::WaitForRequest(Private->EPOC_WsEventStatus); //Markus: I added this and ...
Private->EPOC_RedrawEventStatus = KRequestPending;
Private->EPOC_WsSession.RedrawReady(&Private->EPOC_RedrawEventStatus);
SDL_TRACE("SDL:RedrawEventStatus");
User::WaitForRequest(Private->EPOC_RedrawEventStatus); //...this, if not catches a stray event is risen
//if there are active objects used, or confucing
//actions with User::WaitForAnyRequest
Private->EPOC_WsWindow.PointerFilter(EPointerFilterDrag, 0);
Private->EPOC_ScreenOffset = TPoint(0, 0);
#if defined(__WINS__) || defined(TEST_BM_DRAW)
LockHeap(Private->EPOC_Bitmap); // Lock bitmap heap
#endif
SDL_TRACE("SDL:DrawBackground");
DrawBackground(_this); // Clear screen
#if defined(__WINS__) || defined(TEST_BM_DRAW)
UnlockHeap(Private->EPOC_Bitmap); // Unlock bitmap heap
#endif
//!! TODO: error handling
//if (ret != KErrNone)
// return(-1);
//else
return(0);
}
SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 /*flags*/)
{
if (format->BitsPerPixel == 12 || format->BitsPerPixel == 8)
return Private->SDL_modelist;
return NULL;
}
int EPOC_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
{
if ((firstcolor+ncolors) > 256)
return -1;
// SDL_TRACE1("colors %d", (TDisplayModeUtils::NumDisplayModeColors(Private->EPOC_DisplayMode)));
if(TDisplayModeUtils::NumDisplayModeColors(Private->EPOC_DisplayMode) == 4096)
{
// Set 12 bit palette
for(int i = firstcolor; i < ncolors; i++)
{
// 4k value: 0000 rrrr gggg bbbb
TUint32 color4K = (colors[i].r & 0x0000f0) << 4;
color4K |= (colors[i].g & 0x0000f0);
color4K |= (colors[i].b & 0x0000f0) >> 4;
EPOC_HWPalette_256_to_Screen[i] = color4K;
}
}
else if(TDisplayModeUtils::NumDisplayModeColors(Private->EPOC_DisplayMode) == 65536)
{
for(int i = firstcolor; i < ncolors; i++)
{
// 64k-colour displays effectively support RGB values
// with 5 bits allocated to red, 6 to green and 5 to blue
// 64k value: rrrr rggg gggb bbbb
TUint32 color64K = (colors[i].r & 0x0000f8) << 8;
color64K |= (colors[i].g & 0x0000fc) << 3;
color64K |= (colors[i].b & 0x0000f8) >> 3;
EPOC_HWPalette_256_to_Screen[i] = color64K;
}
}
else if(TDisplayModeUtils::NumDisplayModeColors(Private->EPOC_DisplayMode) == 16777216)
{
for(int i = firstcolor; i < ncolors; i++)
{
// 16M-colour
//0000 0000 rrrr rrrr gggg gggg bbbb bbbb
TUint32 color16M = colors[i].r << 16;
color16M |= colors[i].g << 8;
color16M |= colors[i].b;
EPOC_HWPalette_256_to_Screen[i] = color16M;
}
}
else
{
return -2;
}
return(0);
}
SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 /*flags*/)
{
SDL_TRACE("SDL:EPOC_SetVideoMode");
/* Check parameters */
#ifdef SYMBIAN_CRYSTAL
if (! (bpp == 8 || bpp == 12 || bpp == 16) &&
(
(width == 640 && height == 200) ||
(width == 640 && height == 400) ||
(width == 640 && height == 480) ||
(width == 320 && height == 200) ||
(width == 320 && height == 240)
)) {
SDL_SetError("Requested video mode is not supported");
return NULL;
}
#else // SYMBIAN_SERIES60
if (! (bpp == 8 || bpp == 12 || bpp == 16) &&
(
(width == 320 && height == 200) ||
(width == 320 && height == 240) ||
(width == 256 && height == 192) ||
(width == 176 && height == 208) ||
(width == 208 && height == 176) || // Rotated
(width == 160 && height == 144)
)) {
SDL_SetError("Requested video mode is not supported");
return NULL;
}
#endif
if (current && current->pixels) {
free(current->pixels);
current->pixels = NULL;
}
if ( ! SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
return(NULL);
}
/* Set up the new mode framebuffer */
if (bpp == 8)
current->flags = (SDL_FULLSCREEN|SDL_SWSURFACE|SDL_PREALLOC|SDL_HWPALETTE);
else // 12 bpp, 16 bpp
current->flags = (SDL_FULLSCREEN|SDL_SWSURFACE|SDL_PREALLOC);
current->w = width;
current->h = height;
int numBytesPerPixel = ((bpp-1)>>3) + 1;
current->pitch = numBytesPerPixel * width; // Number of bytes in scanline
current->pixels = malloc(width * height * numBytesPerPixel);
memset(current->pixels, 0, width * height * numBytesPerPixel);
/* Set the blit function */
_this->UpdateRects = EPOC_DirectUpdate;
/*
* Logic for getting suitable screen dimensions, offset, scaling and orientation
*/
int w = current->w;
int h = current->h;
// Rotate, if the screen does not fit horizontally and it is landscape screen
/*
if ((width>Private->EPOC_ScreenSize.iWidth) && (width>height)) {
Private->EPOC_ScreenOrientation = CFbsBitGc::EGraphicsOrientationRotated270;
w = current->h;
h = current->w;
}
*/
// Get nearest stepwise scale values for width and height. The smallest supported scaled screen is 1/2.
TInt scaleValue = 0;
Private->EPOC_ScreenXScaleValue = 1;
Private->EPOC_ScreenYScaleValue = 1;
if (w > Private->EPOC_ScreenSize.iWidth) {
// Find the biggest scale value that result the width that fits in the screen HW
for (scaleValue = 2; scaleValue++;) {
TInt scaledWidth = (w * (scaleValue-1))/scaleValue;
if (scaledWidth > Private->EPOC_ScreenSize.iWidth)
break;
}
Private->EPOC_ScreenXScaleValue = Max(2, scaleValue - 1);
w = (w * (Private->EPOC_ScreenXScaleValue-1))/Private->EPOC_ScreenXScaleValue;
}
if (h > Private->EPOC_ScreenSize.iHeight) {
// Find the biggest scale value that result the height that fits in the screen HW
for (scaleValue = 2; scaleValue++;) {
TInt scaledHeight = (h * (scaleValue-1))/scaleValue;
if (scaledHeight > Private->EPOC_ScreenSize.iHeight)
break;
}
Private->EPOC_ScreenYScaleValue = Max(2, scaleValue - 1);
h = (h * (Private->EPOC_ScreenYScaleValue-1))/Private->EPOC_ScreenYScaleValue;
}
/* Centralize game window on device screen */
Private->EPOC_ScreenOffset.iX = (Private->EPOC_ScreenSize.iWidth - w) / 2;
if (Private->EPOC_ScreenOffset.iX < 0)
Private->EPOC_ScreenOffset.iX = 0;
Private->EPOC_ScreenOffset.iY = (Private->EPOC_ScreenSize.iHeight - h) / 2;
if (Private->EPOC_ScreenOffset.iY < 0)
Private->EPOC_ScreenOffset.iY = 0;
SDL_TRACE1("View width %d", w);
SDL_TRACE1("View height %d", h);
SDL_TRACE1("View bmode %d", bpp);
SDL_TRACE1("View s %d", scaleValue);
SDL_TRACE1("View x %d", Private->EPOC_ScreenOffset.iX);
SDL_TRACE1("View y %d", Private->EPOC_ScreenOffset.iY);
/* We're done */
return(current);
}
void RedrawWindowL(_THIS)
{
#if defined(__WINS__) || defined(TEST_BM_DRAW)
LockHeap(Private->EPOC_Bitmap); // Lock bitmap heap
Private->EPOC_WindowGc->Activate(Private->EPOC_WsWindow);
#endif
int w = _this->screen->w;
int h = _this->screen->h;
if (Private->EPOC_ScreenOrientation == CFbsBitGc::EGraphicsOrientationRotated270) {
w = _this->screen->h;
h = _this->screen->w;
}
if ((w < Private->EPOC_ScreenSize.iWidth)
|| (h < Private->EPOC_ScreenSize.iHeight)) {
DrawBackground(_this);
}
/* Tell the system that something has been drawn */
TRect rect = TRect(Private->EPOC_WsWindow.Size());
Private->EPOC_WsWindow.Invalidate(rect);
#if defined(__WINS__) || defined(TEST_BM_DRAW)
Private->EPOC_WsWindow.BeginRedraw(rect);
Private->EPOC_WindowGc->BitBlt(TPoint(), Private->EPOC_Bitmap);
Private->EPOC_WsWindow.EndRedraw();
Private->EPOC_WindowGc->Deactivate();
UnlockHeap(Private->EPOC_Bitmap);; // Unlock bitmap heap
Private->EPOC_WsSession.Flush();
#endif
/* Draw current buffer */
SDL_Rect fullScreen;
fullScreen.x = 0;
fullScreen.y = 0;
fullScreen.w = _this->screen->w;
fullScreen.h = _this->screen->h;
EPOC_DirectUpdate(_this, 1, &fullScreen);
}
void DrawBackground(_THIS)
{
/* Draw background */
#if defined(__WINS__) || defined(TEST_BM_DRAW)
//warning heap is not locked! - a function calling must ensure that it's ok
TUint16* screenBuffer = (TUint16*)Private->EPOC_Bitmap->DataAddress();
#else
TUint16* screenBuffer = (TUint16*)Private->EPOC_FrameBuffer;
#endif
// Draw black background
Mem::FillZ(screenBuffer, Private->EPOC_BytesPerScreen);
#if 0
for (int y = 0; y < Private->EPOC_ScreenSize.iHeight; y++) {
for (int x = 0; x < Private->EPOC_ScreenSize.iWidth; x++) {
#ifdef SYMBIAN_CRYSTAL
const TUint16 color = 0; // ((x+y)>>1) & 0xf; /* Draw blue stripes pattern, because in e.g. 320x200 mode there is a big background area*/
#else // SYMBIAN_SERIES60
const TUint16 color = 0; /* Draw black background */
#endif
*screenBuffer++ = color;
}
}
#endif
}
/* We don't actually allow hardware surfaces other than the main one */
static int EPOC_AllocHWSurface(_THIS, SDL_Surface* /*surface*/)
{
return(-1);
}
static void EPOC_FreeHWSurface(_THIS, SDL_Surface* /*surface*/)
{
return;
}
static int EPOC_LockHWSurface(_THIS, SDL_Surface* /*surface*/)
{
return(0);
}
static void EPOC_UnlockHWSurface(_THIS, SDL_Surface* /*surface*/)
{
return;
}
static int EPOC_FlipHWSurface(_THIS, SDL_Surface* /*surface*/)
{
return(0);
}
static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
{
//TInt focusWindowGroupId = Private->EPOC_WsSession.GetFocusWindowGroup();//these are async services
// if (focusWindowGroupId != Private->EPOC_WsWindowGroupID) { //for that cannot be called from
//SDL threads ???
if (!Private->EPOC_IsWindowFocused)
{
/* Force focus window to redraw again for cleaning away SDL screen graphics */
/*
TInt pos = Private->EPOC_WsWindowGroup.OrdinalPosition();
Private->EPOC_WsWindowGroup.SetOrdinalPosition(0, KMaxTInt);
TRect rect = TRect(Private->EPOC_WsWindow.Size());
Private->EPOC_WsWindow.Invalidate(rect);
Private->EPOC_WsWindowGroup.SetOrdinalPosition(pos, ECoeWinPriorityNormal);
*/ /* If this is not the topmost window, wait here! Sleep for 1 second to give cpu time to
multitasking and poll for being the topmost window.
*/
// if (Private->EPOC_WsSession.GetFocusWindowGroup() != Private->EPOC_WsWindowGroupID) {
/* !!TODO: Could call GetRedraw() etc. for WsSession and redraw the screen if needed. That might be
needed if a small dialog comes in front of Game screen.
*/
// while (Private->EPOC_WsSession.GetFocusWindowGroup() != Private->EPOC_WsWindowGroupID)
SDL_PauseAudio(1);
SDL_Delay(1000);
return;
// }
// RedrawWindowL(_this);
}
SDL_PauseAudio(0);
// if we are not focused, do not draw
// if (!Private->EPOC_IsWindowFocused)
// return;
#if defined(__WINS__) || defined(TEST_BM_DRAW)
TBitmapUtil lock(Private->EPOC_Bitmap);
lock.Begin(TPoint(0,0)); // Lock bitmap heap
Private->EPOC_WindowGc->Activate(Private->EPOC_WsWindow);
TUint16* screenBuffer = (TUint16*)Private->EPOC_Bitmap->DataAddress();
#else
TUint16* screenBuffer = (TUint16*)Private->EPOC_FrameBuffer;
#endif
if (Private->EPOC_ScreenOrientation == CFbsBitGc::EGraphicsOrientationRotated270)
DirectDrawRotated(_this, numrects, rects, screenBuffer);
else
DirectDraw(_this, numrects, rects, screenBuffer);
#if defined(__WINS__) || defined(TEST_BM_DRAW)
TRect rect = TRect(Private->EPOC_WsWindow.Size());
Private->EPOC_WsWindow.Invalidate(rect);
Private->EPOC_WsWindow.BeginRedraw(rect);
Private->EPOC_WindowGc->BitBlt(TPoint(), Private->EPOC_Bitmap);
Private->EPOC_WsWindow.EndRedraw();
Private->EPOC_WindowGc->Deactivate();
lock.End(); // Unlock bitmap heap
Private->EPOC_WsSession.Flush();
#else
#ifndef SYMBIAN_CRYSTAL
// This is not needed in Crystal. What is the performance penalty in SERIES60?
TRect rect2 = TRect(Private->EPOC_WsWindow.Size());
Private->EPOC_DrawDevice->UpdateRegion(rect2); // Should we update rects parameter area only??
Private->EPOC_DrawDevice->Update();
#endif
#endif
/* Update virtual cursor. !!Do not yet work properly
Private->EPOC_WsSession.SetPointerCursorPosition(Private->EPOC_WsSession.PointerCursorPosition());
*/
/*static int foo = 1;
for ( int i=0; i < numrects; ++i ) {
const SDL_Rect& currentRect = rects[i];
SDL_Rect rect2;
rect2.x = currentRect.x;
rect2.y = currentRect.y;
rect2.w = currentRect.w;
rect2.h = currentRect.h;
if (rect2.w <= 0 || rect2.h <= 0)
continue;
foo++;
if((foo % 200) == 0)
{
SDL_TRACE1("foo %d", foo);
CFbsBitmap* b = new (ELeave) CFbsBitmap;
SDL_TRACE1("bee %d", (int)b);
int e = b->Create(TSize(currentRect.w, currentRect.h), Private->EPOC_DisplayMode);
SDL_TRACE1("err %d", e);
if(e != KErrNone)
User::Panic(_L("damn"), e);
TBitmapUtil u(b);
u.Begin(TPoint(0, 0));
TUint32* d = b->DataAddress();
SDL_TRACE1("addr %d", (int)d);
for(TInt o = 0; o < currentRect.h; o++)
for(TInt p = 0; p < currentRect.w; p++)
{
u.SetPos(TPoint(p, o));
u.SetPixel(0xFFFF);
}
SDL_TRACE1("w %d", (int)currentRect.w);
SDL_TRACE1("h %d", (int)currentRect.h);
SDL_TRACE1("addr %d", (int)Private->EPOC_DisplayMode);
const TUint f = (TUint)Private->EPOC_FrameBuffer;
const TUint y = (TUint)Private->EPOC_BytesPerScreen;
SDL_TRACE1("frame %u", f);
SDL_TRACE1("bytes %u", y);
Mem::Copy(d, Private->EPOC_FrameBuffer, Private->EPOC_BytesPerScreen);
SDL_TRACE("kopied");
u.End();
TBuf<32> name;
name.Format(_L("C:\\nokia\\images\\doom%d.mbm"), (foo / 200));
e= b->Save(name);
if(e != KErrNone)
User::Panic(_L("damned"), e);
delete b;
}}*/
}
void DirectDraw(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer)
{
TInt i;
const TInt sourceNumBytesPerPixel = ((_this->screen->format->BitsPerPixel-1)>>3) + 1;
const TPoint fixedOffset = Private->EPOC_ScreenOffset;
const TInt screenW = _this->screen->w;
const TInt screenH = _this->screen->h;
const TInt sourceScanlineLength = screenW;
const TInt targetScanlineLength = Private->EPOC_ScreenSize.iWidth;
/* Render the rectangles in the list */
for ( i=0; i < numrects; ++i ) {
const SDL_Rect& currentRect = rects[i];
SDL_Rect rect2;
rect2.x = currentRect.x;
rect2.y = currentRect.y;
rect2.w = currentRect.w;
rect2.h = currentRect.h;
if (rect2.w <= 0 || rect2.h <= 0) /* sanity check */
continue;
/* All variables are measured in pixels */
/* Check rects validity, i.e. upper and lower bounds */
TInt maxX = Min(screenW - 1, rect2.x + rect2.w - 1);
TInt maxY = Min(screenH - 1, rect2.y + rect2.h - 1);
if (maxX < 0 || maxY < 0) /* sanity check */
continue;
/* Clip from bottom */
maxY = Min(maxY, Private->EPOC_ScreenSize.iHeight-1);
/* TODO: Clip from the right side */
const TInt sourceRectWidth = maxX - rect2.x + 1;
const TInt sourceRectWidthInBytes = sourceRectWidth * sourceNumBytesPerPixel;
const TInt sourceRectHeight = maxY - rect2.y + 1;
const TInt sourceStartOffset = rect2.x + rect2.y * sourceScanlineLength;
const TUint skipValue = 1; // no skip
TInt targetStartOffset = fixedOffset.iX + rect2.x + (fixedOffset.iY +rect2.y) * targetScanlineLength;
// Nokia7650 native mode: 12 bpp --> 12 bpp
//
switch (_this->screen->format->BitsPerPixel)
{
case 12:
{
TUint16* bitmapLine = (TUint16*)_this->screen->pixels + sourceStartOffset;
TUint16* screenMemory = screenBuffer + targetStartOffset;
if (skipValue == 1)
{
for(TInt y = 0 ; y < sourceRectHeight ; y++)
{
Mem::Copy(screenMemory, bitmapLine, sourceRectWidthInBytes);
}
bitmapLine += sourceScanlineLength;
screenMemory += targetScanlineLength;
}
else
{
for(TInt y = 0 ; y < sourceRectHeight ; y++)
{
//TODO: optimize: separate loops for 1, 2 and n skip. Mem::Copy() can be used in unscaled case.
TUint16* bitmapPos = bitmapLine; /* 2 bytes per pixel */
TUint16* screenMemoryLinePos = screenMemory; /* 2 bytes per pixel */
for(TInt x = 0 ; x < sourceRectWidth ; x++)
{
__ASSERT_DEBUG(screenMemory < (screenBuffer + Private->EPOC_ScreenSize.iWidth * Private->EPOC_ScreenSize.iHeight), User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(screenMemory >= screenBuffer, User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(bitmapLine < ((TUint16*)_this->screen->pixels + (_this->screen->w * _this->screen->h)), User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(bitmapLine >= (TUint16*)_this->screen->pixels, User::Panic(_L("SDL"), KErrCorrupt));
*screenMemoryLinePos++ = *bitmapPos;
bitmapPos+=skipValue;
}
bitmapLine += sourceScanlineLength;
screenMemory += targetScanlineLength;
}
}
}
break;
// 256 color paletted mode: 8 bpp --> 12 bpp
//
default:
{
if(Private->EPOC_BytesPerPixel <= 2)
{
TUint8* bitmapLine = (TUint8*)_this->screen->pixels + sourceStartOffset;
TUint16* screenMemory = screenBuffer + targetStartOffset;
for(TInt y = 0 ; y < sourceRectHeight ; y++)
{
TUint8* bitmapPos = bitmapLine; /* 1 byte per pixel */
TUint16* screenMemoryLinePos = screenMemory; /* 2 bytes per pixel */
/* Convert each pixel from 256 palette to 4k color values */
for(TInt x = 0 ; x < sourceRectWidth ; x++)
{
__ASSERT_DEBUG(screenMemoryLinePos < (screenBuffer + (Private->EPOC_ScreenSize.iWidth * Private->EPOC_ScreenSize.iHeight)), User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(screenMemoryLinePos >= screenBuffer, User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(bitmapPos < ((TUint8*)_this->screen->pixels + (_this->screen->w * _this->screen->h)), User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(bitmapPos >= (TUint8*)_this->screen->pixels, User::Panic(_L("SDL"), KErrCorrupt));
*screenMemoryLinePos++ = EPOC_HWPalette_256_to_Screen[*bitmapPos++];
// bitmapPos+=skipValue; //TODO: optimize: separate loops for 1, 2 and n skip
}
bitmapLine += sourceScanlineLength;
screenMemory += targetScanlineLength;
}
}
else
{
TUint8* bitmapLine = (TUint8*)_this->screen->pixels + sourceStartOffset;
TUint32* screenMemory = reinterpret_cast<TUint32*>(screenBuffer + targetStartOffset);
for(TInt y = 0 ; y < sourceRectHeight ; y++)
{
TUint8* bitmapPos = bitmapLine; /* 1 byte per pixel */
TUint32* screenMemoryLinePos = screenMemory; /* 2 bytes per pixel */
/* Convert each pixel from 256 palette to 4k color values */
for(TInt x = 0 ; x < sourceRectWidth ; x++)
{
__ASSERT_DEBUG(screenMemoryLinePos < (reinterpret_cast<TUint32*>(screenBuffer) + (Private->EPOC_ScreenSize.iWidth * Private->EPOC_ScreenSize.iHeight)), User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(screenMemoryLinePos >= reinterpret_cast<TUint32*>(screenBuffer), User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(bitmapPos < ((TUint8*)_this->screen->pixels + (_this->screen->w * _this->screen->h)), User::Panic(_L("SDL"), KErrCorrupt));
__ASSERT_DEBUG(bitmapPos >= (TUint8*)_this->screen->pixels, User::Panic(_L("SDL"), KErrCorrupt));
*screenMemoryLinePos++ = EPOC_HWPalette_256_to_Screen[*bitmapPos++];
// bitmapPos+=skipValue; //TODO: optimize: separate loops for 1, 2 and n skip
}
bitmapLine += sourceScanlineLength;
screenMemory += targetScanlineLength;
}
}
}
} // switch
} // for
}
/*
void DirectDraw(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer)
{
TInt i;
const TInt sourceNumBytesPerPixel = ((_this->screen->format->BitsPerPixel-1)>>3) + 1;
const TPoint fixedOffset = Private->EPOC_ScreenOffset;
const TInt screenW = _this->screen->w;
const TInt screenH = _this->screen->h;
const TInt sourceScanlineLength = screenW;
const TInt targetScanlineLength = Private->EPOC_ScreenSize.iWidth;
/* Render the rectangles in the list */
/* for ( i=0; i < numrects; ++i ) {
const SDL_Rect& currentRect = rects[i];
SDL_Rect rect2;
rect2.x = currentRect.x;
rect2.y = currentRect.y;
rect2.w = currentRect.w;
rect2.h = currentRect.h;
if (rect2.w <= 0 || rect2.h <= 0) /* sanity check */
/* continue;
/* All variables are measured in pixels */
/* Check rects validity, i.e. upper and lower bounds */
/* TInt maxX = Min(screenW - 1, rect2.x + rect2.w - 1);
TInt maxY = Min(screenH - 1, rect2.y + rect2.h - 1);
if (maxX < 0 || maxY < 0) /* sanity check */
/* continue;
/* Clip from bottom */
/* maxY = Min(maxY, Private->EPOC_ScreenSize.iHeight-1);
/* TODO: Clip from the right side */
/* TInt sourceRectWidth = maxX - rect2.x + 1;
const TInt sourceRectWidthInBytes = sourceRectWidth * sourceNumBytesPerPixel;
const TInt sourceRectHeight = maxY - rect2.y + 1;
const TInt sourceStartOffset = rect2.x + rect2.y * sourceScanlineLength;
const TUint skipValue = Private->EPOC_ScreenXScaleValue; //1; // no skip
const TInt targetStartOffset = // = (fixedOffset.iX + (rect2.x / skipValue) + (fixedOffset.iY + rect2.y) * targetScanlineLength ) ;
(skipValue > 1 ?
(fixedOffset.iX + (rect2.x / skipValue) + (fixedOffset.iY + rect2.y) * targetScanlineLength ) :
(fixedOffset.iX + rect2.x + (fixedOffset.iY + rect2.y) * targetScanlineLength ));
__ASSERT_DEBUG(skipValue >= 1, User::Panic(KLibName, KErrArgument));
// Nokia7650 native mode: 12 bpp --> 12 bpp
//
switch (_this->screen->format->BitsPerPixel)
{
case 12:
{
TUint16* bitmapLine = (TUint16*)_this->screen->pixels + sourceStartOffset;
TUint16* screenMemory = screenBuffer + targetStartOffset;
if (skipValue == 1)
{
for(TInt y = 0 ; y < sourceRectHeight ; y++)
{
Mem::Copy(screenMemory, bitmapLine, sourceRectWidthInBytes);
}
bitmapLine += sourceScanlineLength;
screenMemory += targetScanlineLength;
}
else
{
for(TInt y = 0 ; y < sourceRectHeight ; y++)
{
//TODO: optimize: separate loops for 1, 2 and n skip. Mem::Copy() can be used in unscaled case.
TUint16* bitmapPos = bitmapLine; /* 2 bytes per pixel */
/* TUint16* screenMemoryLinePos = screenMemory; /* 2 bytes per pixel */
/* for(TInt x = 0 ; x < sourceRectWidth ; x++)
{
__ASSERT_DEBUG(screenMemory < (screenBuffer + Private->EPOC_ScreenSize.iWidth * Private->EPOC_ScreenSize.iHeight), User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(screenMemory >= screenBuffer, User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(bitmapLine < ((TUint16*)_this->screen->pixels + (_this->screen->w * _this->screen->h)), User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(bitmapLine >= (TUint16*)_this->screen->pixels, User::Panic(KLibName, KErrCorrupt));
*screenMemoryLinePos++ = *bitmapPos;
bitmapPos+=skipValue;
}
bitmapLine += sourceScanlineLength;
screenMemory += targetScanlineLength;
}
}
}
break;
// 256 color paletted mode: 8 bpp --> 12 bpp
//
default:
{
TUint8* bitmapLine = (TUint8*)_this->screen->pixels + sourceStartOffset;
TUint16* screenMemory = screenBuffer + targetStartOffset;
if (skipValue > 1)
sourceRectWidth /= skipValue;
#if defined __MARM_ARMI__
__asm volatile("
mov %4, %4, lsl #1 @ targetScanLineLength is in pixels, we need it in bytes
1:
mov r6, %0 @ bitmapLine
mov r7, %2 @ screenMemory
mov r8, %6 @ sourceRectWidth
2:
ldrb r4, [%0], %7 @ r4 = *bitmapPos; bitmapPos += skipValue
ldr r5, [%1, r4, lsl #2] @ only 16 lower bits actually used
subs r8, r8, #1 @ x--
strh r5, [%2], #2 @ *screenMemoryLinePos++ = r4
bne 2b
add %0, r6, %3 @ bitmapLine += sourceScanlineLength
add %2, r7, %4 @ screenMemory += targetScanlineLength
subs %5, %5, #1 @ sourceRectHeight--
bne 1b
"
: // no output
// %0 %1 %2 %3 %4 %5 %6 %7
: "r" (bitmapLine), "r" (&EPOC_HWPalette_256_to_Screen[0]), "r" (screenMemory), "r" (sourceScanlineLength), "r" (targetScanlineLength), "r" (sourceRectHeight), "r" (sourceRectWidth), "r" (skipValue)
: "r4", "r5", "r6", "r7", "r8"
);
#else
for(TInt y = 0 ; y < sourceRectHeight ; y++)
{
TUint8* bitmapPos = bitmapLine; /* 1 byte per pixel */
/* TUint16* screenMemoryLinePos = screenMemory; /* 2 bytes per pixel */
/* Convert each pixel from 256 palette to 4k color values */
/* for (TInt x = 0 ; x < sourceRectWidth ; x++)
{
//__ASSERT_DEBUG(screenMemoryLinePos < (screenBuffer + (Private->EPOC_ScreenSize.iWidth * Private->EPOC_ScreenSize.iHeight)), User::Panic(KLibName, KErrCorrupt));
//__ASSERT_DEBUG(screenMemoryLinePos >= screenBuffer, User::Panic(KLibName, KErrCorrupt));
//__ASSERT_DEBUG(bitmapPos < ((TUint8*)_this->screen->pixels + (_this->screen->w * _this->screen->h)), User::Panic(KLibName, KErrCorrupt));
//__ASSERT_DEBUG(bitmapPos >= (TUint8*)_this->screen->pixels, User::Panic(KLibName, KErrCorrupt));
*screenMemoryLinePos++ = EPOC_HWPalette_256_to_Screen[*bitmapPos];
bitmapPos += skipValue;
}
bitmapLine += sourceScanlineLength;
screenMemory += targetScanlineLength;
}
//#endif
}
} // switch
} // for
}
*/
void DirectDrawRotated(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer)
{
TInt i;
// TInt sourceNumBytesPerPixel = ((_this->screen->format->BitsPerPixel-1)>>3) + 1;
TPoint fixedScreenOffset = Private->EPOC_ScreenOffset;
TInt bufferW = _this->screen->w;
TInt bufferH = _this->screen->h;
TInt ScreenW = Private->EPOC_ScreenSize.iWidth;
// TInt ScreenH = Private->EPOC_ScreenSize.iWidth;
TInt sourceW = bufferW;
TInt sourceH = bufferH;
TInt targetW = ScreenW - fixedScreenOffset.iX * 2;
// TInt targetH = ScreenH - fixedScreenOffset.iY * 2;
TInt sourceScanlineLength = bufferW;
TInt targetScanlineLength = Private->EPOC_ScreenSize.iWidth;
/* Render the rectangles in the list */
for ( i=0; i < numrects; ++i ) {
SDL_Rect rect2;
const SDL_Rect& currentRect = rects[i];
rect2.x = currentRect.x;
rect2.y = currentRect.y;
rect2.w = currentRect.w;
rect2.h = currentRect.h;
if (rect2.w <= 0 || rect2.h <= 0) /* sanity check */
continue;
/* All variables are measured in pixels */
/* Check rects validity, i.e. upper and lower bounds */
TInt maxX = Min(sourceW - 1, rect2.x + rect2.w - 1);
TInt maxY = Min(sourceH - 1, rect2.y + rect2.h - 1);
if (maxX < 0 || maxY < 0) /* sanity check */
continue;
/* Clip from bottom */
//maxX = Min(maxX, Private->EPOC_ScreenSize.iHeight-1);
/* TODO: Clip from the right side */
TInt sourceRectWidth = maxX - rect2.x + 1;
// TInt sourceRectWidthInBytes = sourceRectWidth * sourceNumBytesPerPixel;
TInt sourceRectHeight = maxY - rect2.y + 1;
TInt sourceStartOffset = rect2.x + rect2.y * sourceScanlineLength;
TInt targetStartOffset = fixedScreenOffset.iX + (targetW-1 - rect2.y) + (fixedScreenOffset.iY +rect2.x) * targetScanlineLength;
// Nokia7650 native mode: 12 bpp --> 12 bpp
if (_this->screen->format->BitsPerPixel == 12) {
/* !!TODO: not yet implemented
TUint16* bitmapLine = (TUint16*)_this->screen->pixels + sourceStartOffset;
TUint16* screenMemory = screenBuffer + targetStartOffset;
for(TInt y = 0 ; y < sourceRectHeight ; y++) {
//TODO: optimize: separate loops for 1, 2 and n skip
//Mem::Copy(screenMemory, bitmapLine, sourceRectWidthInBytes);
TUint16* bitmapPos = bitmapLine; // 2 bytes per pixel
TUint16* screenMemoryLinePos = screenMemory; // 2 bytes per pixel
for(TInt x = 0 ; x < sourceRectWidth ; x++) {
__ASSERT_DEBUG(screenMemory < (screenBuffer + Private->EPOC_ScreenSize.iWidth * Private->EPOC_ScreenSize.iHeight), User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(screenMemory >= screenBuffer, User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(bitmapLine < ((TUint16*)_this->screen->pixels + (_this->screen->w * _this->screen->h)), User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(bitmapLine >= (TUint16*)_this->screen->pixels, User::Panic(KLibName, KErrCorrupt));
*screenMemoryLinePos = *bitmapPos;
bitmapPos++;
screenMemoryLinePos += targetScanlineLength;
}
bitmapLine += sourceScanlineLength;
screenMemory--;
}
*/
}
// 256 color paletted mode: 8 bpp --> 12 bpp
else {
TUint8* bitmapLine = (TUint8*)_this->screen->pixels + sourceStartOffset;
TUint16* screenMemory = screenBuffer + targetStartOffset;
TInt screenXScaleValue = Private->EPOC_ScreenXScaleValue;
TInt debug_ycount=0;
for(TInt y = 0 ; y < sourceRectHeight ; y++) {
if(--screenXScaleValue) {
TUint8* bitmapPos = bitmapLine; /* 1 byte per pixel */
TUint16* screenMemoryLinePos = screenMemory; /* 2 bytes per pixel */
TInt screenYScaleValue = Private->EPOC_ScreenYScaleValue;
TInt debug_xcount=0;
/* Convert each pixel from 256 palette to 4k color values */
for(TInt x = 0 ; x < sourceRectWidth ; x++) {
if(--screenYScaleValue) {
__ASSERT_DEBUG(screenMemoryLinePos < (screenBuffer + (Private->EPOC_ScreenSize.iWidth * Private->EPOC_ScreenSize.iHeight)), User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(screenMemoryLinePos >= screenBuffer, User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(bitmapPos < ((TUint8*)_this->screen->pixels + (_this->screen->w * _this->screen->h)), User::Panic(KLibName, KErrCorrupt));
__ASSERT_DEBUG(bitmapPos >= (TUint8*)_this->screen->pixels, User::Panic(KLibName, KErrCorrupt));
*screenMemoryLinePos = TUint16(EPOC_HWPalette_256_to_Screen[*bitmapPos]);
screenMemoryLinePos += targetScanlineLength; debug_xcount++;
}
else
screenYScaleValue = Private->EPOC_ScreenYScaleValue;
bitmapPos++;
}
screenMemory--; debug_ycount++;
} // endif
else
screenXScaleValue = Private->EPOC_ScreenXScaleValue;
bitmapLine += sourceScanlineLength;
}
}
}
}
/* Note: If we are terminated, this could be called in the middle of
another SDL video routine -- notably UpdateRects.
*/
void EPOC_VideoQuit(_THIS)
{
int i;
/* Free video mode lists */
for ( i=0; i<SDL_NUMMODES; ++i ) {
if ( Private->SDL_modelist[i] != NULL ) {
free(Private->SDL_modelist[i]);
Private->SDL_modelist[i] = NULL;
}
}
if ( _this->screen && (_this->screen->flags & SDL_HWSURFACE) ) {
/* Direct screen access, no memory buffer */
_this->screen->pixels = NULL;
}
if (_this->screen && _this->screen->pixels) {
free(_this->screen->pixels);
_this->screen->pixels = NULL;
}
/* Free Epoc resources */
/* Disable events for me */
if (Private->EPOC_WsEventStatus != KRequestPending)
Private->EPOC_WsSession.EventReadyCancel();
if (Private->EPOC_RedrawEventStatus != KRequestPending)
Private->EPOC_WsSession.RedrawReadyCancel();
#if defined(__WINS__) || defined(TEST_BM_DRAW)
delete Private->EPOC_Bitmap;
Private->EPOC_Bitmap = NULL;
#else
#endif
#ifndef SYMBIAN_CRYSTAL
free(Private->EPOC_DrawDevice);
#endif
if (Private->EPOC_WsWindow.WsHandle())
Private->EPOC_WsWindow.Close();
if (Private->EPOC_WsWindowGroup.WsHandle())
Private->EPOC_WsWindowGroup.Close();
delete Private->EPOC_WindowGc;
Private->EPOC_WindowGc = NULL;
delete Private->EPOC_WsScreen;
Private->EPOC_WsScreen = NULL;
if (Private->EPOC_WsSession.WsHandle())
Private->EPOC_WsSession.Close();
}
WMcursor *EPOC_CreateWMCursor(_THIS, Uint8* /*data*/, Uint8* /*mask*/, int /*w*/, int /*h*/, int /*hot_x*/, int /*hot_y*/)
{
return (WMcursor *) 9210; // it's ok to return something unuseful but true
}
void EPOC_FreeWMCursor(_THIS, WMcursor* /*cursor*/)
{
/* Disable virtual cursor */
HAL::Set(HAL::EMouseState, HAL::EMouseState_Invisible);
Private->EPOC_WsSession.SetPointerCursorMode(EPointerCursorNone);
}
int EPOC_ShowWMCursor(_THIS, WMcursor *cursor)
{
if (cursor == (WMcursor *)9210) {
/* Enable virtual cursor */
Private->EPOC_WsSession.SetPointerCursorMode(EPointerCursorNormal);
if (isCursorVisible)
HAL::Set(HAL::EMouseState, HAL::EMouseState_Visible);
else
Private->EPOC_WsSession.SetPointerCursorMode(EPointerCursorNone);
}
else {
/* Disable virtual cursor */
HAL::Set(HAL::EMouseState, HAL::EMouseState_Invisible);
Private->EPOC_WsSession.SetPointerCursorMode(EPointerCursorNone);
}
return(1);
}
}; // extern "C"
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
#ifndef _SDL_epocvideo_h
#define _SDL_epocvideo_h
#ifndef EKA2
#include"SDL_epocvideo_org.h"
#else
#include"SDL_epocvideo2.h"
#endif
#endif
#include "epoc_sdl.h"
#include <stdio.h>
#undef NULL
extern "C" {
//#define DEBUG_TRACE_ENABLED
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_keysym.h"
#include "SDL_keyboard.h"
#include "SDL_events_c.h"
#include "SDL_timer.h"
} /* extern "C" */
#include "SDL_epocvideo.h"
#include "SDL_epocevents_c.h"
#include "sdlepocapi.h"
#include <eikenv.h>
#include<bautils.h>
extern "C"
{
static SDL_keysym *TranslateKey(_THIS, int scancode, SDL_keysym *keysym);
}
//extern "C" {
/* The translation tables from a console scancode to a SDL keysym */
static SDLKey keymap[MAX_SCANCODE];
static SDL_keysym *TranslateKey(_THIS, int scancode, SDL_keysym *keysym);
void DisableKeyBlocking(_THIS);
//} /* extern "C" */
SDLKey* KeyMap()
{
return keymap;
}
TBool isCursorVisible = EFalse;
void ResetKeyMap()
{
int i;
/* Initialize the key translation table */
for ( i=0; i<SDL_TABLESIZE(keymap); ++i )
keymap[i] = SDLK_UNKNOWN;
/* Numbers */
for ( i = 0; i<32; ++i ){
keymap[' ' + i] = (SDLKey)(SDLK_SPACE+i);
}
/* e.g. Alphabet keys */
for ( i = 0; i<32; ++i ){
keymap['A' + i] = (SDLKey)(SDLK_a+i);
}
keymap[EStdKeyBackspace] = SDLK_BACKSPACE;
keymap[EStdKeyTab] = SDLK_TAB;
keymap[EStdKeyEnter] = SDLK_RETURN;
keymap[EStdKeyEscape] = SDLK_ESCAPE;
keymap[EStdKeySpace] = SDLK_SPACE;
keymap[EStdKeyPause] = SDLK_PAUSE;
keymap[EStdKeyHome] = SDLK_HOME;
keymap[EStdKeyEnd] = SDLK_END;
keymap[EStdKeyPageUp] = SDLK_PAGEUP;
keymap[EStdKeyPageDown] = SDLK_PAGEDOWN;
keymap[EStdKeyDelete] = SDLK_DELETE;
keymap[EStdKeyUpArrow] = SDLK_UP;
keymap[EStdKeyDownArrow] = SDLK_DOWN;
keymap[EStdKeyLeftArrow] = SDLK_LEFT;
keymap[EStdKeyRightArrow] = SDLK_RIGHT;
keymap[EStdKeyCapsLock] = SDLK_CAPSLOCK;
keymap[EStdKeyLeftShift] = SDLK_LSHIFT;
keymap[EStdKeyRightShift] = SDLK_RSHIFT;
keymap[EStdKeyLeftAlt] = SDLK_LALT;
keymap[EStdKeyRightAlt] = SDLK_RALT;
keymap[EStdKeyLeftCtrl] = SDLK_LCTRL;
keymap[EStdKeyRightCtrl] = SDLK_RCTRL;
keymap[EStdKeyLeftFunc] = SDLK_LMETA;
keymap[EStdKeyRightFunc] = SDLK_RMETA;
keymap[EStdKeyInsert] = SDLK_INSERT;
keymap[EStdKeyComma] = SDLK_COMMA;
keymap[EStdKeyFullStop] = SDLK_PERIOD;
keymap[EStdKeyForwardSlash] = SDLK_SLASH;
keymap[EStdKeyBackSlash] = SDLK_BACKSLASH;
keymap[EStdKeySemiColon] = SDLK_SEMICOLON;
keymap[EStdKeySingleQuote] = SDLK_QUOTE;
keymap[EStdKeyHash] = SDLK_HASH;
keymap[EStdKeySquareBracketLeft] = SDLK_LEFTBRACKET;
keymap[EStdKeySquareBracketRight] = SDLK_RIGHTBRACKET;
keymap[EStdKeyMinus] = SDLK_MINUS;
keymap[EStdKeyEquals] = SDLK_EQUALS;
keymap[EStdKeyF1] = SDLK_F1;
keymap[EStdKeyF2] = SDLK_F2;
keymap[EStdKeyF3] = SDLK_F3;
keymap[EStdKeyF4] = SDLK_F4;
keymap[EStdKeyF5] = SDLK_F5;
keymap[EStdKeyF6] = SDLK_F6;
keymap[EStdKeyF7] = SDLK_F7;
keymap[EStdKeyF8] = SDLK_F8;
keymap[EStdKeyF9] = SDLK_F9;
keymap[EStdKeyF10] = SDLK_F10;
keymap[EStdKeyF11] = SDLK_F11;
keymap[EStdKeyF12] = SDLK_F12;
keymap[EStdKeyXXX] = SDLK_RETURN; /* "fire" key */
keymap[EStdKeyDevice3] = SDLK_RETURN; /* "fire" key */
keymap[EStdKeyNkpAsterisk] = SDLK_ASTERISK;
keymap[EStdKeyYes] = SDLK_HOME; /* "call" key */
keymap[EStdKeyNo] = SDLK_END; /* "end call" key */
keymap[EStdKeyDevice0] = SDLK_SPACE; /* right menu key */
keymap[EStdKeyDevice1] = SDLK_ESCAPE; /* left menu key */
keymap[EStdKeyDevice2] = SDLK_POWER; /* power key */
keymap[EStdKeyMenu] = SDLK_MENU; // menu key
keymap[EStdKeyDevice6] = SDLK_LEFT; // Rocker (joystick) left
keymap[EStdKeyDevice7] = SDLK_RIGHT; // Rocker (joystick) right
keymap[EStdKeyDevice8] = SDLK_UP; // Rocker (joystick) up
keymap[EStdKeyDevice9] = SDLK_DOWN; // Rocker (joystick) down
keymap[EStdKeyLeftFunc] = SDLK_LALT; //chr?
keymap[EStdKeyRightFunc] = SDLK_RALT;
keymap[EStdKeyDeviceA] = SDLK_RETURN; /* "fire" key */
///////////////////////////////////////////////////////////
/*
RFs fs;
if(KErrNone == fs.Connect())
{
RArray<TInt> array;
TRAPD(err, ReadL(fs, array));
if(err == KErrNone && array.Count() > 0)
{
SDLKey temp[MAX_SCANCODE];
Mem::Copy(temp, keymap, MAX_SCANCODE * sizeof(SDLKey));
for(TInt k = 0; k < array.Count(); k+= 2)
{
const TInt oldval = array[k];
const TInt newval = array[k + 1];
if(oldval >= 0 && oldval < MAX_SCANCODE && newval >= 0 && newval < MAX_SCANCODE)
{
keymap[oldval] = temp[newval];
}
}
}
array.Close();
}
fs.Close();*/
///////////////////////////////////////////////////////////
keymap[EStdKeyNumLock] = SDLK_NUMLOCK;
keymap[EStdKeyScrollLock] = SDLK_SCROLLOCK;
keymap[EStdKeyNkpForwardSlash] = SDLK_KP_DIVIDE;
keymap[EStdKeyNkpAsterisk] = SDLK_KP_MULTIPLY;
keymap[EStdKeyNkpMinus] = SDLK_KP_MINUS;
keymap[EStdKeyNkpPlus] = SDLK_KP_PLUS;
keymap[EStdKeyNkpEnter] = SDLK_KP_ENTER;
keymap[EStdKeyNkp1] = SDLK_KP1;
keymap[EStdKeyNkp2] = SDLK_KP2;
keymap[EStdKeyNkp3] = SDLK_KP3;
keymap[EStdKeyNkp4] = SDLK_KP4;
keymap[EStdKeyNkp5] = SDLK_KP5;
keymap[EStdKeyNkp6] = SDLK_KP6;
keymap[EStdKeyNkp7] = SDLK_KP7;
keymap[EStdKeyNkp8] = SDLK_KP8;
keymap[EStdKeyNkp9] = SDLK_KP9;
keymap[EStdKeyNkp0] = SDLK_KP0;
keymap[EStdKeyNkpFullStop] = SDLK_KP_PERIOD;
/*
keymap[EStdKeyMenu] = SDLK_MENU; should be, but not yet
keymap[EStdKeyBacklightOn] =
keymap[EStdKeyBacklightOff] =
keymap[EStdKeyBacklightToggle] =
keymap[EStdKeyIncContrast] =
keymap[EStdKeyDecContrast] =
keymap[EStdKeySliderDown] =
keymap[EStdKeySliderUp] =
keymap[EStdKeyDictaphonePlay] =
keymap[EStdKeyDictaphoneStop] =
keymap[EStdKeyDictaphoneRecord] =
keymap[EStdKeyHelp] =
keymap[EStdKeyOff] =
keymap[EStdKeyDial] =
keymap[EStdKeyIncVolume] =
keymap[EStdKeyDecVolume] =
keymap[EStdKeyDevice0] =
keymap[EStdKeyDevice1] =
keymap[EStdKeyDevice2] =
keymap[EStdKeyDevice3] =
keymap[EStdKeyDevice4] =
keymap[EStdKeyDevice5] =
keymap[EStdKeyDevice6] =
keymap[EStdKeyDevice7] =
keymap[EStdKeyDevice8] =
keymap[EStdKeyDevice9] =
keymap[EStdKeyDeviceA] =
keymap[EStdKeyDeviceB] =
keymap[EStdKeyDeviceC] =
keymap[EStdKeyDeviceD] =
keymap[EStdKeyDeviceE] =
keymap[EStdKeyDeviceF] =
keymap[EStdKeyApplication0] =
keymap[EStdKeyApplication1] =
keymap[EStdKeyApplication2] =
keymap[EStdKeyApplication3] =
keymap[EStdKeyApplication4] =
keymap[EStdKeyApplication5] =
keymap[EStdKeyApplication6] =
keymap[EStdKeyApplication7] =
keymap[EStdKeyApplication8] =
keymap[EStdKeyApplication9] =
keymap[EStdKeyApplicationA] =
keymap[EStdKeyApplicationB] =
keymap[EStdKeyApplicationC] =
keymap[EStdKeyApplicationD] =
keymap[EStdKeyApplicationE] =
keymap[EStdKeyApplicationF] =
keymap[EStdKeyYes] =
keymap[EStdKeyNo] =
keymap[EStdKeyIncBrightness] =
keymap[EStdKeyDecBrightness] =
keymap[EStdKeyCaseOpen] =
keymap[EStdKeyCaseClose] = */
}
int EPOC_HandleWsEvent(_THIS, const TWsEvent& aWsEvent)
{
int posted = 0;
SDL_keysym keysym;
// SDL_TRACE1("hws %d", aWsEvent.Type());
switch (aWsEvent.Type())
{
case EEventPointer: /* Mouse pointer events */
{
/* const TPointerCursorMode mode = EpocSdlEnv::PointerMode();
if(mode == EPointerCursorNone)
{
return 0; //TODO: Find out why events are get despite of cursor should be off
}
*/
const TPointerEvent* pointerEvent = aWsEvent.Pointer();
const TPoint mousePos = EpocSdlEnv::WindowCoordinates(pointerEvent->iPosition);
/*!! TODO Pointer do not yet work properly
//SDL_TRACE1("SDL: EPOC_HandleWsEvent, pointerEvent->iType=%d", pointerEvent->iType); //!!
if (Private->EPOC_ShrinkedHeight) {
mousePos.iY <<= 1; // Scale y coordinate to shrinked screen height
}
if (Private->EPOC_ShrinkedWidth) {
mousePos.iX <<= 1; // Scale x coordinate to shrinked screen width
}
*/
posted += SDL_PrivateMouseMotion(0, 0, mousePos.iX, mousePos.iY); /* Absolute position on screen */
switch (pointerEvent->iType)
{
case TPointerEvent::EButton1Down:
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, 0, 0);
break;
case TPointerEvent::EButton1Up:
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, 0, 0);
break;
case TPointerEvent::EButton2Down:
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_RIGHT, 0, 0);
break;
case TPointerEvent::EButton2Up:
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_RIGHT, 0, 0);
break;
case TPointerEvent::EButton3Down:
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_MIDDLE, 0, 0);
break;
case TPointerEvent::EButton3Up:
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_MIDDLE, 0, 0);
break;
} // switch
break;
}
case EEventKeyDown: /* Key events */
{
#ifdef SYMBIAN_CRYSTAL
// special case: 9300/9500 rocker down, simulate left mouse button
if (aWsEvent.Key()->iScanCode == EStdKeyDeviceA)
{
const TPointerCursorMode mode = Private->EPOC_WsSession.PointerCursorMode();
if(mode != EPointerCursorNone)
posted += SDL_PrivateMouseButton(SDL_PRESSED, SDL_BUTTON_LEFT, 0, 0);
}
#endif
(void*)TranslateKey(_this, aWsEvent.Key()->iScanCode, &keysym);
#ifndef DISABLE_JOYSTICK
/* Special handling */
switch((int)keysym.sym) {
case SDLK_CAPSLOCK:
if (!isCursorVisible) {
/* Enable virtual cursor */
HAL::Set(HAL::EMouseState, HAL::EMouseState_Visible);
}
else {
/* Disable virtual cursor */
HAL::Set(HAL::EMouseState, HAL::EMouseState_Invisible);
}
isCursorVisible = !isCursorVisible;
break;
}
#endif
posted += SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
break;
}
case EEventKeyUp: /* Key events */
{
#ifdef SYMBIAN_CRYSTAL
// special case: 9300/9500 rocker up, simulate left mouse button
if (aWsEvent.Key()->iScanCode == EStdKeyDeviceA)
{
posted += SDL_PrivateMouseButton(SDL_RELEASED, SDL_BUTTON_LEFT, 0, 0);
}
#endif
posted += SDL_PrivateKeyboard(SDL_RELEASED, TranslateKey(_this, aWsEvent.Key()->iScanCode, &keysym));
break;
}
case EEventFocusGained: /* SDL window got focus */
{
Private->iIsWindowFocused = ETrue;
posted += SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS);
/* Draw window background and screen buffer */
DisableKeyBlocking(_this); //Markus: guess why:-)
//RedrawWindowL(_this);
break;
}
case EEventFocusLost: /* SDL window lost focus */
{
Private->iIsWindowFocused = EFalse;
posted += SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS);
break;
}
case EEventModifiersChanged:
{
TModifiersChangedEvent* modEvent = aWsEvent.ModifiersChanged();
TUint modstate = KMOD_NONE;
if (modEvent->iModifiers == EModifierLeftShift)
modstate |= KMOD_LSHIFT;
if (modEvent->iModifiers == EModifierRightShift)
modstate |= KMOD_RSHIFT;
if (modEvent->iModifiers == EModifierLeftCtrl)
modstate |= KMOD_LCTRL;
if (modEvent->iModifiers == EModifierRightCtrl)
modstate |= KMOD_RCTRL;
if (modEvent->iModifiers == EModifierLeftAlt)
modstate |= KMOD_LALT;
if (modEvent->iModifiers == EModifierRightAlt)
modstate |= KMOD_RALT;
if (modEvent->iModifiers == EModifierLeftFunc)
modstate |= KMOD_LMETA;
if (modEvent->iModifiers == EModifierRightFunc)
modstate |= KMOD_RMETA;
if (modEvent->iModifiers == EModifierCapsLock)
modstate |= KMOD_CAPS;
SDL_SetModState(STATIC_CAST(SDLMod,(modstate | KMOD_LSHIFT)));
break;
}
case EEventScreenDeviceChanged:
{
EpocSdlEnv::WaitDeviceChange();
}
break;
default:
break;
}
return posted;
}
extern "C" {
void EPOC_PumpEvents(_THIS)
{
MEventQueue& events = EpocSdlEnv::EventQueue();
while(events.HasData())
{
events.Lock();
//there have to be a copy, so we can release
//lock immediately. HandleWsEvent may cause
//deadlock otherwise.
const TWsEvent event = events.Shift();
events.Unlock();
// const TWsEvent& event = events.Top();
EPOC_HandleWsEvent(_this, event);
// events.Shift();
}
}
void EPOC_InitOSKeymap(_THIS)
{
ResetKeyMap();
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventKeyMapInit ,0);
}
static SDL_keysym *TranslateKey(_THIS, int scancode, SDL_keysym *keysym)
{
// char debug[256];
//SDL_TRACE1("SDL: TranslateKey, scancode=%d", scancode); //!!
/* Set the keysym information */
keysym->scancode = scancode;
if ((scancode >= MAX_SCANCODE) &&
((scancode - ENonCharacterKeyBase + 0x0081) >= MAX_SCANCODE)) {
SDL_SetError("Too big scancode");
keysym->scancode = SDLK_UNKNOWN;
keysym->mod = KMOD_NONE;
return keysym;
}
keysym->mod = SDL_GetModState();
/* Handle function keys: F1, F2, F3 ... */
if (keysym->mod & KMOD_META) {
if (scancode >= 'A' && scancode < ('A' + 24)) { /* first 32 alphabet keys */
switch(scancode) {
case 'Q': scancode = EStdKeyF1; break;
case 'W': scancode = EStdKeyF2; break;
case 'E': scancode = EStdKeyF3; break;
case 'R': scancode = EStdKeyF4; break;
case 'T': scancode = EStdKeyF5; break;
case 'Y': scancode = EStdKeyF6; break;
case 'U': scancode = EStdKeyF7; break;
case 'I': scancode = EStdKeyF8; break;
case 'A': scancode = EStdKeyF9; break;
case 'S': scancode = EStdKeyF10; break;
case 'D': scancode = EStdKeyF11; break;
case 'F': scancode = EStdKeyF12; break;
}
keysym->sym = keymap[scancode];
}
}
if (scancode >= ENonCharacterKeyBase) {
// Non character keys
keysym->sym = keymap[scancode -
ENonCharacterKeyBase + 0x0081]; // !!hard coded
} else {
keysym->sym = keymap[scancode];
}
/* Remap the arrow keys if the device is rotated */
/*
if (Private->EPOC_ScreenOrientation == CFbsBitGc::EGraphicsOrientationRotated270) {
switch(keysym->sym) {
case SDLK_UP: keysym->sym = SDLK_LEFT; break;
case SDLK_DOWN: keysym->sym = SDLK_RIGHT; break;
case SDLK_LEFT: keysym->sym = SDLK_DOWN; break;
case SDLK_RIGHT:keysym->sym = SDLK_UP; break;
}
}
*/
/* If UNICODE is on, get the UNICODE value for the key */
keysym->unicode = 0;
#if 0 // !!TODO:unicode
if ( SDL_TranslateUNICODE )
{
/* Populate the unicode field with the ASCII value */
keysym->unicode = scancode;
}
#endif
//!!
//sprintf(debug, "SDL: TranslateKey: keysym->scancode=%d, keysym->sym=%d, keysym->mod=%d",
// keysym->scancode, keysym->sym, keysym->mod);
//SDL_TRACE(debug); //!!
return(keysym);
}
} /* extern "C" */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_epocvideo.cpp
Epoc based SDL video driver implementation
Markus Mertama
*/
#include "epoc_sdl.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern "C" {
#include "SDL_error.h"
#include "SDL_timer.h"
#include "SDL_video.h"
#undef NULL
#include "SDL_pixels_c.h"
#include "SDL.h"
#include "SDL_mouse.h"
}
#include "SDL_epocvideo.h"
#include "SDL_epocevents_c.h"
#include <coedef.h>
#include <flogger.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikapp.h>
#include "sdlepocapi.h"
////////////////////////////////////////////////////////////////
_LIT(KLibName, "SDL");
void RDebug_Print_b(char* error_str, void* param)
{
TBuf8<128> error8((TUint8*)error_str);
TBuf<128> error;
error.Copy(error8);
#ifndef TRACE_TO_FILE
if (param) //!! Do not work if the parameter is really 0!!
RDebug::Print(error, param);
else
RDebug::Print(error);
#else
if (param) //!! Do not work if the parameter is really 0!!
RFileLogger::WriteFormat(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error, param);
else
RFileLogger::Write(KLibName, _L("SDL.txt"), EFileLoggingModeAppend, error);
#endif
}
extern "C" void RDebug_Print(char* error_str, void* param)
{
RDebug_Print_b(error_str, param);
}
/*
int Debug_AvailMem2()
{
//User::CompressAllHeaps();
TMemoryInfoV1Buf membuf;
User::LeaveIfError(UserHal::MemoryInfo(membuf));
TMemoryInfoV1 minfo = membuf();
return(minfo.iFreeRamInBytes);
}
extern "C" int Debug_AvailMem()
{
return(Debug_AvailMem2());
}
*/
extern "C" {
/* Initialization/Query functions */
static int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat);
static SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
static SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
static int EPOC_SetColors(_THIS, int firstcolor, int ncolors,
SDL_Color *colors);
static void EPOC_VideoQuit(_THIS);
/* Hardware surface functions */
static int EPOC_AllocHWSurface(_THIS, SDL_Surface *surface);
static int EPOC_LockHWSurface(_THIS, SDL_Surface *surface);
static int EPOC_FlipHWSurface(_THIS, SDL_Surface *surface);
static void EPOC_UnlockHWSurface(_THIS, SDL_Surface *surface);
static void EPOC_FreeHWSurface(_THIS, SDL_Surface *surface);
static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
static int EPOC_Available(void);
static SDL_VideoDevice *EPOC_CreateDevice(int devindex);
void DrawBackground(_THIS);
void DirectDraw(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
void DirectDrawRotated(_THIS, int numrects, SDL_Rect *rects, TUint16* screenBuffer);
/* Mouse functions */
static WMcursor *EPOC_CreateWMCursor(_THIS, Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y);
static void EPOC_FreeWMCursor(_THIS, WMcursor *cursor);
static int EPOC_ShowWMCursor(_THIS, WMcursor *cursor);
}
extern "C"
{
struct WMcursor
{
};
}
/* Epoc video driver bootstrap functions */
static int EPOC_Available(void)
{
return 1; /* Always available */
}
static void EPOC_DeleteDevice(SDL_VideoDevice *device)
{
User::Free(device->hidden);
User::Free(device);
}
static SDL_VideoDevice *EPOC_CreateDevice(int /*devindex*/)
{
SDL_VideoDevice *device;
SDL_TRACE("SDL:EPOC_CreateDevice");
/* Allocate all variables that we free on delete */
device = static_cast<SDL_VideoDevice*>(User::Alloc(sizeof(SDL_VideoDevice)));
if ( device )
{
Mem::FillZ(device, (sizeof *device));
device->hidden = static_cast<struct SDL_PrivateVideoData*>
(User::Alloc((sizeof *device->hidden)));
}
if ( (device == NULL) || (device->hidden == NULL) )
{
SDL_OutOfMemory();
if ( device ) {
User::Free(device);
}
return(0);
}
Mem::FillZ(device->hidden, (sizeof *device->hidden));
/* Set the function pointers */
device->VideoInit = EPOC_VideoInit;
device->ListModes = EPOC_ListModes;
device->SetVideoMode = EPOC_SetVideoMode;
device->SetColors = EPOC_SetColors;
device->UpdateRects = NULL;
device->VideoQuit = EPOC_VideoQuit;
device->AllocHWSurface = EPOC_AllocHWSurface;
device->CheckHWBlit = NULL;
device->FillHWRect = NULL;
device->SetHWColorKey = NULL;
device->SetHWAlpha = NULL;
device->LockHWSurface = EPOC_LockHWSurface;
device->UnlockHWSurface = EPOC_UnlockHWSurface;
device->FlipHWSurface = EPOC_FlipHWSurface;
device->FreeHWSurface = EPOC_FreeHWSurface;
device->SetIcon = NULL;
device->SetCaption = NULL;
device->GetWMInfo = NULL;
device->FreeWMCursor = EPOC_FreeWMCursor;
device->CreateWMCursor = EPOC_CreateWMCursor;
device->ShowWMCursor = EPOC_ShowWMCursor;
device->WarpWMCursor = NULL;
device->InitOSKeymap = EPOC_InitOSKeymap;
device->PumpEvents = EPOC_PumpEvents;
device->free = EPOC_DeleteDevice;
return device;
}
VideoBootStrap EPOC_bootstrap = {
"epoc\0\0\0", "EPOC system",
EPOC_Available, EPOC_CreateDevice
};
void DisableKeyBlocking(_THIS)
{
EpocSdlEnv::Request(EpocSdlEnv::EDisableKeyBlocking);
}
void ConstructWindowL(_THIS)
{
SDL_TRACE("SDL:ConstructWindowL");
DisableKeyBlocking(_this); //disable key blocking
}
int EPOC_VideoInit(_THIS, SDL_PixelFormat *vformat)
{
/* Construct Epoc window */
ConstructWindowL(_this);
/* Initialise Epoc frame buffer */
const TDisplayMode displayMode = EpocSdlEnv::DisplayMode();
/* The "best" video format should be returned to caller. */
vformat->BitsPerPixel = TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode);
vformat->BytesPerPixel = TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode) / 8;
//?? Private->iWindow->PointerFilter(EPointerFilterDrag, 0);
Private->iScreenPos = TPoint(0, 0);
Private->iRect.x = Private->iScreenPos.iX;
Private->iRect.y = Private->iScreenPos.iY;
const TSize sz = EpocSdlEnv::WindowSize();
Private->iRect.w = sz.iWidth;
Private->iRect.h = sz.iHeight;
Private->iRectPtr = &Private->iRect;
return(0);
}
SDL_Rect **EPOC_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
{
if(flags & SDL_HWSURFACE)
{
if(format->BytesPerPixel != 4) //in HW only full color is supported
return NULL;
}
if(flags & SDL_FULLSCREEN)
{
return &Private->iRectPtr;
}
return (SDL_Rect **)(-1); //everythingisok, unless too small shoes
}
int EPOC_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
{
if ((firstcolor+ncolors) > 256)
return -1;
TUint32 palette[256];
const TDisplayMode mode = EpocSdlEnv::DisplayMode();
if(TDisplayModeUtils::NumDisplayModeColors(mode) == 4096)
{
// Set 12 bit palette
for(int i = firstcolor; i < ncolors; i++)
{
// 4k value: 0000 rrrr gggg bbbb
TUint32 color4K = (colors[i].r & 0x0000f0) << 4;
color4K |= (colors[i].g & 0x0000f0);
color4K |= (colors[i].b & 0x0000f0) >> 4;
palette[i] = color4K;
}
}
else if(TDisplayModeUtils::NumDisplayModeColors(mode) == 65536)
{
for(int i = firstcolor; i < ncolors; i++)
{
// 64k-colour displays effectively support RGB values
// with 5 bits allocated to red, 6 to green and 5 to blue
// 64k value: rrrr rggg gggb bbbb
TUint32 color64K = (colors[i].r & 0x0000f8) << 8;
color64K |= (colors[i].g & 0x0000fc) << 3;
color64K |= (colors[i].b & 0x0000f8) >> 3;
palette[i] = color64K;
}
}
else if(TDisplayModeUtils::NumDisplayModeColors(mode) == 16777216)
{
for(int i = firstcolor; i < ncolors; i++)
{
// 16M-colour
//0000 0000 rrrr rrrr gggg gggg bbbb bbbb
TUint32 color16M = colors[i].r << 16;
color16M |= colors[i].g << 8;
color16M |= colors[i].b;
palette[i] = color16M;
}
}
else
{
return -2;
}
if(EpocSdlEnv::SetPalette(firstcolor, ncolors, palette) == KErrNone)
return 0;
return -1;
}
/*
void AllocHWSurfaceL(CFbsBitmap*& aBitmap, const TDisplayMode& aMode, const TSize& aSize)
{
aBitmap = new (ELeave) CFbsBitmap();
if(KErrNone != aBitmap->CreateHardwareBitmap(aSize, aMode,
EpocSdlEnv::EikonEnv().EikAppUi()->Application()->AppDllUid()))
//...if it fails - should we use wsbitmaps???
{//the good reason to use hw bitmaps is that they wont need lock heap
PANIC_IF_ERROR(aBitmap->Create(aSize, aMode));
}
}
int CreateSurfaceL(_THIS, SDL_Surface* surface)
{
__ASSERT_ALWAYS(Private->iFrame == NULL, PANIC(KErrAlreadyExists));
;
TInt dmode = EColorLast;
TDisplayMode displayMode;
EpocSdlEnv::GetDiplayMode(displayMode);
if(
TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode)
== surface->format->BitsPerPixel)
{
dmode = displayMode;
}
else
{
--dmode;
while(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)) &&
TDisplayModeUtils::NumDisplayModeBitsPerPixel(TDisplayMode(dmode)) !=
surface->format->BitsPerPixel)
--dmode;
}
__ASSERT_ALWAYS(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)), PANIC(KErrNotSupported));
TRAPD(err, AllocHWSurfaceL(Private->iFrame, TDisplayMode(dmode), TSize(surface->w, surface->h)));
return err == KErrNone ? 0 : -1;
}
*/
TDisplayMode GetDisplayMode(TInt aBitsPerPixel)
{
const TDisplayMode displayMode = EpocSdlEnv::DisplayMode();
TInt dmode = EColorLast;
if(
TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode)
== aBitsPerPixel)
{
dmode = displayMode;
}
else
{
--dmode;
while(TDisplayModeUtils::IsDisplayModeColor(TDisplayMode(dmode)) &&
TDisplayModeUtils::NumDisplayModeBitsPerPixel(TDisplayMode(dmode)) !=
aBitsPerPixel)
--dmode;
}
return TDisplayMode(dmode);
}
SDL_Surface *EPOC_SetVideoMode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
const TSize screenSize = EpocSdlEnv::WindowSize(TSize(width, height));
if(width > screenSize.iWidth || height > screenSize.iHeight)
{
if(flags & SDL_FULLSCREEN)
{
width = screenSize.iWidth;
height = screenSize.iHeight;
}
else
return NULL;
}
if(current && current->pixels)
{
// free(current->pixels);
current->pixels = NULL;
}
if(!SDL_ReallocFormat(current, bpp, 0, 0, 0, 0))
{
return(NULL);
}
current->flags = 0;
if(width == screenSize.iWidth && height == screenSize.iHeight)
current->flags |= SDL_FULLSCREEN;
const int numBytesPerPixel = ((bpp-1)>>3) + 1;
current->pitch = numBytesPerPixel * width; // Number of bytes in scanline
/* Set up the new mode framebuffer */
current->flags |= SDL_PREALLOC;
if(bpp <= 8)
current->flags |= SDL_HWPALETTE;
User::Free(Private->iSwSurface);
current->pixels = NULL;
Private->iSwSurface = NULL;
if(flags & SDL_HWSURFACE)
{
current->flags |= SDL_HWSURFACE;
// current->pixels = NULL;
// Private->iSwSurface = NULL;
}
else
{
current->flags |= SDL_SWSURFACE;
const TInt surfacesize = width * height * numBytesPerPixel;
Private->iSwSurfaceSize = TSize(width, height);
delete Private->iSwSurface;
Private->iSwSurface = NULL;
current->pixels = (TUint8*) User::AllocL(surfacesize);
Private->iSwSurface = (TUint8*) current->pixels;
const TInt err = EpocSdlEnv::AllocSwSurface
(TSize(width, height), GetDisplayMode(current->format->BitsPerPixel));
if(err != KErrNone)
return NULL;
}
current->w = width;
current->h = height;
/* Set the blit function */
_this->UpdateRects = EPOC_DirectUpdate;
/*
* Logic for getting suitable screen dimensions, offset, scaling and orientation
*/
/* Centralize game window on device screen */
Private->iScreenPos.iX = Max(0, (screenSize.iWidth - width) / 2);
Private->iScreenPos.iY = Max(0, (screenSize.iHeight - height) / 2);
// delete (Private->iFrame);
// Private->iFrame = NULL;
// TRAPD(err, CreateSurfaceL(_this, current));
// PANIC_IF_ERROR(err);
SDL_TRACE1("View width %d", width);
SDL_TRACE1("View height %d", height);
SDL_TRACE1("View bmode %d", bpp);
SDL_TRACE1("View x %d", Private->iScreenPos.iX);
SDL_TRACE1("View y %d", Private->iScreenPos.iY);
EpocSdlEnv::LockPalette(EFalse);
/* We're done */
return(current);
}
static int EPOC_AllocHWSurface(_THIS, SDL_Surface* surface)
{
return KErrNone == EpocSdlEnv::AllocHwSurface(TSize(surface->w, surface->h), GetDisplayMode(surface->format->BitsPerPixel));
}
static void EPOC_FreeHWSurface(_THIS, SDL_Surface* /*surface*/)
{
}
static int EPOC_LockHWSurface(_THIS, SDL_Surface* surface)
{
if(EpocSdlEnv::IsDsaAvailable())
{
TUint8* address = EpocSdlEnv::LockHwSurface();
if(address != NULL)
{
surface->pixels = address;
return 1;
}
}
return 0;
}
static void EPOC_UnlockHWSurface(_THIS, SDL_Surface* /*surface*/)
{
EpocSdlEnv::UnlockHwSurface();
}
static int EPOC_FlipHWSurface(_THIS, SDL_Surface* /*surface*/)
{
return(0);
}
static void EPOC_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
{
if(EpocSdlEnv::IsDsaAvailable())
{
if(Private->iSwSurface)
{
const TRect target(Private->iScreenPos, Private->iSwSurfaceSize);
for(TInt i = 0; i < numrects ;i++)
{
const TRect rect(TPoint(rects[i].x, rects[i].y),
TSize(rects[i].w, rects[i].h));
if(!EpocSdlEnv::AddUpdateRect(Private->iSwSurface, rect, target))
return; //not succesful
}
EpocSdlEnv::UpdateSwSurface();
}
SDL_PauseAudio(0);
}
else
{
SDL_PauseAudio(1);
EpocSdlEnv::WaitDsaAvailable();
}
}
/* Note: If we are terminated, this could be called in the middle of
another SDL video routine -- notably UpdateRects.
*/
void EPOC_VideoQuit(_THIS)
{
// delete Private->iFrame;
// Private->iFrame = NULL;
User::Free(Private->iSwSurface);
Private->iSwSurface = NULL;
EpocSdlEnv::FreeSurface();
}
WMcursor *EPOC_CreateWMCursor(_THIS, Uint8* /*data*/, Uint8* /*mask*/, int /*w*/, int /*h*/, int /*hot_x*/, int /*hot_y*/)
{
return (WMcursor*) 1; //hii! prevents SDL to view a std cursor
}
void EPOC_FreeWMCursor(_THIS, WMcursor* /*cursor*/)
{
}
int EPOC_ShowWMCursor(_THIS, WMcursor *cursor)
{
return true;
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
#ifndef EPOCVIDEO_H
#define EPOCVIDEO_H
#include<w32std.h>
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_VideoDevice *_this
#define Private _this->hidden
class CFbsBitmap;
struct SDL_VideoDevice;
void DisableKeyBlocking(SDL_VideoDevice*);
struct SDL_PrivateVideoData
{
TPoint iScreenPos;
TBool iIsWindowFocused;
TSize iSwSurfaceSize;
TUint8* iSwSurface;
SDL_Rect iRect; //same info in SDL format
SDL_Rect* iRectPtr;
};
#endif
\ No newline at end of file
#include "dsa.h"
#include "sdlepocapi.h"
#include <cdsb.h>
LOCAL_C TInt BytesPerPixel(TDisplayMode aMode)
{
return ((TDisplayModeUtils::NumDisplayModeBitsPerPixel(aMode) - 1) >> 3) + 1;
}
template<class T>
class CBitmapSurface : public T
{
public:
CBitmapSurface(RWsSession& aSession);
private:
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
~CBitmapSurface();
TUint8* LockSurface();
void UnlockHwSurface();
void CreateSurfaceL();
void Wipe(TInt aLength);
void Free();
void Update(CFbsBitmap& aBmp);
TInt ExternalUpdate();
private:
CFbsBitmap* iBmp;
CFbsBitmap* iCopyBmp;
};
template<class T>
void CBitmapSurface<T>::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
delete iCopyBmp;
iCopyBmp = NULL;
iCopyBmp = new (ELeave) CFbsBitmap();
T::ConstructL(aWindow, aDevice);
}
template<class T>
CBitmapSurface<T>::CBitmapSurface(RWsSession& aSession) : T(aSession)
{
}
template<class T>
void CBitmapSurface<T>::Free()
{
delete iBmp;
iBmp = NULL;
T::Free();
}
template<class T>
CBitmapSurface<T>::~CBitmapSurface()
{
__ASSERT_DEBUG(iBmp == NULL, PANIC(KErrNotReady));
delete iCopyBmp;
}
template<class T>
TUint8* CBitmapSurface<T>::LockSurface()
{
iBmp->LockHeap();
return reinterpret_cast<TUint8*>(iBmp->DataAddress());
}
template<class T>
void CBitmapSurface<T>::UnlockHwSurface()
{
iBmp->UnlockHeap();
T::SetUpdating(EFalse);
Update(*iBmp);
}
template<class T>
void CBitmapSurface<T>::Update(CFbsBitmap& aBmp)
{
if(!T::Blitter(aBmp))
{
if(T::SwSize() == T::HwRect().Size())
T::Gc().BitBlt(T::HwRect().iTl, &aBmp);
else
T::Gc().DrawBitmap(T::HwRect(), &aBmp);
}
T::DrawOverlays();
T::CompleteUpdate();
}
template<class T>
void CBitmapSurface<T>::CreateSurfaceL()
{
Free();
iBmp = new (ELeave) CFbsBitmap();
User::LeaveIfError(iBmp->Create(T::SwSize(), T::DisplayMode()));
T::CreateSurfaceL(*iBmp);
}
template<class T>
void CBitmapSurface<T>::Wipe(TInt aLength) //dont call in drawing
{
iBmp->LockHeap();
Mem::FillZ(iBmp->DataAddress(), aLength);
iBmp->UnlockHeap();
}
template<class T>
TInt CBitmapSurface<T>::ExternalUpdate()
{
if(iCopyBmp->Handle() == 0)
{
const TInt err = iCopyBmp->Duplicate(iBmp->Handle());
if(err != KErrNone)
return err;
}
Update(*iCopyBmp);
return KErrNone;
}
//////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(CDsaBitgdi) : public CDsa
{
public:
CDsaBitgdi(RWsSession& aSession);
protected:
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
CBitmapContext& Gc();
void CompleteUpdate();
~CDsaBitgdi();
void CreateSurfaceL(CFbsBitmap& aBmp);
void Free();
void UnlockHWSurfaceRequestComplete();
private:
void Resume();
CFbsBitGc* iGc;
CFbsDevice* iDevice;
CFbsBitmap* iBitGdiBmp;
CWindowGc* iWinGc;
RWindow* iWindow;
TInt iHandle;
};
CDsaBitgdi::CDsaBitgdi(RWsSession& aSession) : CDsa(aSession)
{
}
CDsaBitgdi::~CDsaBitgdi()
{
delete iWinGc;
delete iBitGdiBmp;
}
void CDsaBitgdi::CompleteUpdate()
{
EpocSdlEnv::Request(CDsa::ERequestUpdate);
}
void CDsaBitgdi::UnlockHWSurfaceRequestComplete()
{
if(iHandle == 0)
return;
if(iBitGdiBmp == NULL)
{
iBitGdiBmp = new CFbsBitmap();
if(iBitGdiBmp == NULL)
return;
iBitGdiBmp->Duplicate(iHandle);
}
iWindow->Invalidate();
iWindow->BeginRedraw();
iWinGc->Activate(*iWindow);
iWinGc->BitBlt(TPoint(0, 0), iBitGdiBmp);
iWinGc->Deactivate();
iWindow->EndRedraw();
}
void CDsaBitgdi::Resume()
{
Start();
}
CBitmapContext& CDsaBitgdi::Gc()
{
return *iGc;
}
void CDsaBitgdi::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
delete iBitGdiBmp;
iBitGdiBmp = NULL;
delete iWinGc;
iWinGc = NULL;
iHandle = 0;
iWindow = &aWindow;
User::LeaveIfError(aDevice.CreateContext(iWinGc));
CDsa::ConstructL(aWindow, aDevice);
Start();
}
void CDsaBitgdi::CreateSurfaceL(CFbsBitmap& aBmp)
{
iDevice = CFbsBitmapDevice::NewL(&aBmp);
User::LeaveIfError(iDevice->CreateContext(iGc));
iHandle = aBmp.Handle();
}
void CDsaBitgdi::Free()
{
delete iGc;
iGc = NULL;
delete iDevice;
iDevice = NULL;
}
////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(CDsaBase) : public CDsa, public MDirectScreenAccess
{
protected:
inline CDirectScreenAccess& Dsa() const;
CDsaBase(RWsSession& aSession);
~CDsaBase();
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
void Stop();
void Resume();
CBitmapContext& Gc();
protected:
CDirectScreenAccess* iDsa;
private:
void AbortNow(RDirectScreenAccess::TTerminationReasons aReason);
void Restart(RDirectScreenAccess::TTerminationReasons aReason);
private:
void RestartL();
};
inline CDirectScreenAccess& CDsaBase::Dsa() const
{
return *iDsa;
}
CDsaBase::CDsaBase(RWsSession& aSession) : CDsa(aSession)
{
}
CBitmapContext& CDsaBase::Gc()
{
return *Dsa().Gc();
}
void CDsaBase::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
CDsa::ConstructL(aWindow, aDevice);
if(iDsa != NULL)
{
iDsa->Cancel();
delete iDsa;
iDsa = NULL;
}
iDsa = CDirectScreenAccess::NewL(
Session(),
aDevice,
aWindow,
*this);
RestartL();
}
void CDsaBase::Resume()
{
if(Stopped())
Restart(RDirectScreenAccess::ETerminateRegion);
}
CDsaBase::~CDsaBase()
{
if(iDsa != NULL)
{
iDsa->Cancel();
}
delete iDsa;
}
void CDsaBase::RestartL()
{
iDsa->StartL();
const RRegion* r = iDsa->DrawingRegion();
const TRect rect = r->BoundingRect();
iDsa->Gc()->SetClippingRegion(r);
if(rect != ScreenRect())
{
return ;
}
SetTargetRect();
RecreateL();
Start();
}
void CDsaBase::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/)
{
Stop();
}
void CDsaBase::Restart(RDirectScreenAccess::TTerminationReasons aReason)
{
if(aReason == RDirectScreenAccess::ETerminateRegion) //auto restart
{
TRAPD(err, RestartL());
PANIC_IF_ERROR(err);
}
}
void CDsaBase::Stop()
{
CDsa::Stop();
iDsa->Cancel();
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(TDsa)
{
public:
inline TDsa(const CDsa& aDsa);
inline TBool IsFlip() const;
inline TBool IsTurn() const;
inline const TSize& SwSize() const;
inline void Copy(TUint32* aTarget, const TUint8* aSrc, TInt aBytes, TInt aHeight) const;
private:
const CDsa& iDsa;
};
inline TDsa::TDsa(const CDsa& aDsa) : iDsa(aDsa)
{
}
inline TBool TDsa::IsTurn() const
{
return iDsa.iStateFlags & CDsa::EOrientation90;
}
inline TBool TDsa::IsFlip() const
{
return iDsa.iStateFlags & CDsa::EOrientation180;
}
inline const TSize& TDsa::SwSize() const
{
return iDsa.SwSize();
}
inline void TDsa::Copy(TUint32* aTarget, const TUint8* aSrc, TInt aBytes, TInt aHeight) const
{
iDsa.iCopyFunction(iDsa, aTarget, aSrc, aBytes, aHeight);
}
template<class T, class S>
void ClipCopy(const TDsa& iDsa, TUint8* aTarget,
const TUint8* aSource,
const TRect& aUpdateRect,
const TRect& aSourceRect)
{
const S* source = reinterpret_cast<const S*>(aSource);
const TInt lineWidth = aSourceRect.Width();
source += (aUpdateRect.iTl.iY * lineWidth);
const TInt sourceStartOffset = aUpdateRect.iTl.iX;
source += sourceStartOffset;
T* targetPtr = reinterpret_cast<T*>(aTarget);
const TInt scanLineWidth = iDsa.SwSize().iWidth;
targetPtr += (aSourceRect.iTl.iY + aUpdateRect.iTl.iY ) * scanLineWidth;
const TInt targetStartOffset = (aUpdateRect.iTl.iX + aSourceRect.iTl.iX);
targetPtr += targetStartOffset;
const TInt height = aUpdateRect.Height();
const TInt lineMove = iDsa.IsTurn() ? 1 : lineWidth;
const TInt copyLen = aUpdateRect.Width();
if(iDsa.IsFlip())
{
targetPtr += scanLineWidth * (height - 1);
for(TInt i = 0; i < height; i++) //source is always smaller
{
iDsa.Copy(reinterpret_cast<TUint32*>(targetPtr), reinterpret_cast<const TUint8*>(source), copyLen, height);
source += lineMove;
targetPtr -= scanLineWidth;
}
}
else
{
for(TInt i = 0; i < height; i++) //source is always smaller
{
iDsa.Copy(reinterpret_cast<TUint32*>(targetPtr), reinterpret_cast<const TUint8*>(source), copyLen, height);
source += lineMove;
targetPtr += scanLineWidth; // >> 2;
}
}
}
NONSHARABLE_CLASS(CDsaA) : public CDsaBase
{
public:
CDsaA(RWsSession& aSession);
protected:
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
void CompleteUpdate();
void CreateSurfaceL(CFbsBitmap& aBmp);
void Free();
void UnlockHWSurfaceRequestComplete();
};
CDsaA::CDsaA(RWsSession& aSession) : CDsaBase(aSession)
{
}
void CDsaA::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
CDsaBase::ConstructL(aWindow, aDevice);
}
void CDsaA::CompleteUpdate()
{
iDsa->ScreenDevice()->Update();
}
void CDsaA::CreateSurfaceL(CFbsBitmap& /*aBmp*/)
{
}
void CDsaA::Free()
{
}
void CDsaA::UnlockHWSurfaceRequestComplete()
{
PANIC(KErrNotSupported);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(MDsbObs)
{
public:
virtual void SurfaceReady() = 0;
virtual CDirectScreenBitmap& Dsb() = 0;
};
NONSHARABLE_CLASS(CDsbSurface) : public CActive
{
public:
CDsbSurface(MDsbObs& aDsb);
TUint8* Address();
void Complete();
~CDsbSurface();
private:
void RunL();
void DoCancel();
private:
MDsbObs& iDsb;
TUint8* iAddress;
};
CDsbSurface::CDsbSurface(MDsbObs& aDsb) : CActive(CActive::EPriorityHigh) , iDsb(aDsb)
{
CActiveScheduler::Add(this);
}
CDsbSurface::~CDsbSurface()
{
Cancel();
}
void CDsbSurface::Complete()
{
if(iAddress != NULL && !IsActive())
{
iAddress = NULL;
SetActive();
iDsb.Dsb().EndUpdate(iStatus);
}
}
TUint8* CDsbSurface::Address()
{
if(iAddress == NULL && !IsActive())
{
TAcceleratedBitmapInfo info;
if(KErrNone == iDsb.Dsb().BeginUpdate(info))
iAddress = info.iAddress;
}
return iAddress;
}
void CDsbSurface::RunL()
{
iDsb.SurfaceReady();
}
void CDsbSurface::DoCancel()
{
//empty
}
NONSHARABLE_CLASS(CDsaB) : public CDsaBase,
public MDsbObs
{
public:
CDsaB(RWsSession& aSession, TInt aFlags);
private:
~CDsaB();
TUint8* LockSurface();
void UnlockHWSurfaceRequestComplete();
void UnlockHwSurface();
void CreateSurfaceL();
void Wipe(TInt aLength);
void RecreateL();
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
CDirectScreenBitmap& Dsb();
void SurfaceReady();
TInt ExternalUpdate();
private:
CDsbSurface* iSurface1;
CDsbSurface* iSurface2;
CDirectScreenBitmap* iDsb;
TInt iType;
};
CDsaB::CDsaB(RWsSession& aSession, TInt aFlags) : CDsaBase(aSession), iType(aFlags)
{
}
void CDsaB::UnlockHWSurfaceRequestComplete()
{
iSurface1->Complete();
if(iSurface2 != NULL)
iSurface2->Complete();
}
void CDsaB::CreateSurfaceL()
{
__ASSERT_ALWAYS(SwSize() == HwRect().Size(), PANIC(KErrNotSupported));
}
void CDsaB::Wipe(TInt aLength) //dont call in drawing
{
TUint8* addr = LockSurface();
if(addr != NULL)
{
Mem::FillZ(addr, aLength);
UnlockHwSurface();
}
}
void CDsaB::UnlockHwSurface()
{
EpocSdlEnv::Request(CDsa::ERequestUpdate);
}
TUint8* CDsaB::LockSurface()
{
TUint8* addr = iSurface1->Address();
if(addr == NULL && iSurface2 != NULL)
addr = iSurface2->Address();
SetUpdating(addr == NULL);
return addr;
}
void CDsaB::SurfaceReady()
{
SetUpdating(EFalse);
}
CDirectScreenBitmap& CDsaB::Dsb()
{
return *iDsb;
}
void CDsaB::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
if(iDsb == NULL)
iDsb = CDirectScreenBitmap::NewL();
CDsaBase::ConstructL(aWindow, aDevice);
if(iSurface1 == NULL)
iSurface1 = new (ELeave) CDsbSurface(*this);
if(iSurface2 == NULL && iType & CDirectScreenBitmap::EDoubleBuffer)
iSurface2 = new (ELeave) CDsbSurface(*this);
}
CDsaB::~CDsaB()
{
delete iSurface1;
delete iSurface2;
delete iDsb;
}
void CDsaB::RecreateL()
{
iDsb->Close();
iDsb->Create(HwRect(), CDirectScreenBitmap::TSettingsFlags(iType));
}
TInt CDsaB::ExternalUpdate()
{
if(LockSurface())
{
UnlockHWSurfaceRequestComplete();
return KErrNone;
}
return KErrNotReady;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
CDsa* CDsa::CreateL(RWsSession& aSession)
{
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSB))
{
TInt flags = CDirectScreenBitmap::ENone;
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSBDoubleBuffer))
flags |= CDirectScreenBitmap::EDoubleBuffer;
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSBIncrementalUpdate))
flags |= CDirectScreenBitmap::EIncrementalUpdate;
return new (ELeave) CDsaB(aSession, flags);
}
else if(EpocSdlEnv::Flags(CSDL::EDrawModeGdi))
{
return new (ELeave) CBitmapSurface<CDsaBitgdi>(aSession);
}
else
{
return new (ELeave) CBitmapSurface<CDsaA>(aSession);
}
}
void CDsa::RecreateL()
{
}
void CDsa::Free()
{
}
TSize CDsa::WindowSize() const
{
TSize size = iSwSize;
if(iStateFlags & EOrientation90)
{
const TInt tmp = size.iWidth;
size.iWidth = size.iHeight;
size.iHeight = tmp;
}
return size;
}
void CDsa::SetSuspend()
{
iStateFlags |= ESdlThreadSuspend;
}
void CDsa::SetUpdating(TBool aUpdate)
{
if(aUpdate)
iStateFlags |= EUpdating;
else
iStateFlags &= ~EUpdating;
}
TBool CDsa::Stopped() const
{
return (iStateFlags & ESdlThreadExplicitStop);
}
void CDsa::SetOrientation(CSDL::TOrientationMode aOrientation)
{
TInt flags = 0;
switch(aOrientation)
{
case CSDL::EOrientation90:
flags = EOrientation90;
break;
case CSDL::EOrientation180:
flags = EOrientation180;
break;
case CSDL::EOrientation270:
flags = EOrientation90 | EOrientation180;
break;
case CSDL::EOrientation0:
flags = 0;
break;
}
if(flags != (iStateFlags & EOrientationFlags))
{
iStateFlags |= EOrientationChanged;
iNewFlags = flags; //cannot be set during drawing...
}
}
CDsa::~CDsa()
{
iOverlays.Close();
User::Free(iLut256);
}
void CDsa::ConstructL(RWindow& aWindow, CWsScreenDevice& /*aDevice*/)
{
if(iLut256 == NULL)
iLut256 = (TUint32*) User::AllocL(256 * sizeof(TUint32));
iTargetMode = aWindow.DisplayMode();
iTargetBpp = BytesPerPixel(DisplayMode());
iScreenRect = TRect(aWindow.Position(), aWindow.Size());
SetTargetRect();
}
void CDsa::DrawOverlays()
{
const TInt last = iOverlays.Count() - 1;
for(TInt i = last; i >= 0 ; i--)
iOverlays[i].iOverlay->Draw(Gc(), HwRect(), SwSize());
}
TInt CDsa::AppendOverlay(MOverlay& aOverlay, TInt aPriority)
{
TInt i;
for(i = 0; i < iOverlays.Count() && iOverlays[i].iPriority < aPriority; i++)
{}
const TOverlay overlay = {&aOverlay, aPriority};
return iOverlays.Insert(overlay, i);
}
TInt CDsa::RemoveOverlay(MOverlay& aOverlay)
{
for(TInt i = 0; i < iOverlays.Count(); i++)
{
if(iOverlays[i].iOverlay == &aOverlay)
{
iOverlays.Remove(i);
return KErrNone;
}
}
return KErrNotFound;
}
void CDsa::LockPalette(TBool aLock)
{
if(aLock)
iStateFlags |= EPaletteLocked;
else
iStateFlags &= ~EPaletteLocked;
}
TInt CDsa::SetPalette(TInt aFirst, TInt aCount, TUint32* aPalette)
{
if(iLut256 == NULL)
return KErrNotFound;
const TInt count = aCount - aFirst;
if(count > 256)
return KErrArgument;
if(iStateFlags & EPaletteLocked)
return KErrNone;
for(TInt i = aFirst; i < count; i++) //not so busy here:-)
{
iLut256[i] = aPalette[i];
}
return KErrNone;
}
CDsa::CDsa(RWsSession& aSession) :
iSession(aSession),
iStateFlags(0)
{
// CActiveScheduler::Add(this);
iCFTable[0] = CopyMem;
iCFTable[1] = CopyMemFlipReversed;
iCFTable[2] = CopyMemReversed;
iCFTable[3] = CopyMemFlip;
iCFTable[4] = Copy256;
iCFTable[5] = Copy256FlipReversed;
iCFTable[6] = Copy256Reversed;
iCFTable[7] = Copy256Flip;
iCFTable[8] = CopySlow;
iCFTable[9] = CopySlowFlipReversed;
iCFTable[10] = CopySlowReversed;
iCFTable[11] = CopySlowFlip;
}
RWsSession& CDsa::Session()
{
return iSession;
}
TInt CDsa::RedrawRequest()
{
if(!(iStateFlags & (EUpdating) && (iStateFlags & ERunning)))
{
return ExternalUpdate();
}
return KErrNotReady;
}
TUint8* CDsa::LockHwSurface()
{
if((iStateFlags & EUpdating) == 0) //else frame is skipped
{
return LockSurface();
}
return NULL;
}
/*
void CDsa::RunL()
{
iStateFlags &= ~EUpdating;
}
void CDsa::DoCancel()
{
iStateFlags &= ~EUpdating;
//nothing can do, just wait?
}
*/
TInt CDsa::AllocSurface(TBool aHwSurface, const TSize& aSize, TDisplayMode aMode)
{
if(aHwSurface && aMode != DisplayMode())
return KErrArgument;
iSourceMode = aMode;
iSourceBpp = BytesPerPixel(aMode);
const TSize size = WindowSize();
if(aSize.iWidth > size.iWidth)
return KErrTooBig;
if(aSize.iHeight > size.iHeight)
return KErrTooBig;
TRAPD(err, CreateSurfaceL());
if(err != KErrNone)
return err;
SetCopyFunction();
return KErrNone;
}
void CDsa::CreateZoomerL(const TSize& aSize)
{
iSwSize = aSize;
iStateFlags |= EResizeRequest;
CreateSurfaceL();
SetTargetRect();
}
/*
void SaveBmp(const TDesC& aName, const TAny* aData, TInt aLength, const TSize& aSz, TDisplayMode aMode)
{
CFbsBitmap* s = new CFbsBitmap();
s->Create(aSz, aMode);
s->LockHeap();
TUint32* addr = s->DataAddress();
Mem::Copy(addr, aData, aLength);
s->UnlockHeap();
s->Save(aName);
s->Reset();
delete s;
}
void SaveBmp(const TDesC& aName, const TUint32* aData, const TSize& aSz)
{
CFbsBitmap* s = new CFbsBitmap();
s->Create(aSz, EColor64K);
TBitmapUtil bmp(s);
bmp.Begin(TPoint(0, 0));
for(TInt j = 0; j < aSz.iHeight; j++)
{
bmp.SetPos(TPoint(0, j));
for(TInt i = 0; i < aSz.iWidth; i++)
{
bmp.SetPixel(*aData);
aData++;
bmp.IncXPos();
}
}
bmp.End();
s->Save(aName);
s->Reset();
delete s;
}
TBuf<16> FooName(TInt aFoo)
{
TBuf<16> b;
b.Format(_L("C:\\pic%d.mbm"), aFoo);
return b;
}
*/
void CDsa::ClipCopy(TUint8* aTarget,
const TUint8* aSource,
const TRect& aUpdateRect,
const TRect& aSourceRect) const
{
const TDsa dsa(*this);
switch(iSourceBpp)
{
case 1:
::ClipCopy<TUint32, TUint8>(dsa, aTarget, aSource, aUpdateRect, aSourceRect);
break;
case 2:
::ClipCopy<TUint32, TUint16>(dsa, aTarget, aSource, aUpdateRect, aSourceRect);
break;
case 4:
::ClipCopy<TUint32, TUint32>(dsa, aTarget, aSource, aUpdateRect, aSourceRect);
break;
}
}
void CDsa::Wipe() //dont call in drawing
{
if(IsDsaAvailable())
Wipe(iTargetBpp * SwSize().iWidth * SwSize().iHeight);
}
void CDsa::SetCopyFunction()
{
//calculate offset to correct function in iCFTable according to given parameters
TInt function = 0;
const TInt KCopyFunctions = 4;
const TInt KOffsetToNative = 0;
const TInt KOffsetTo256 = KOffsetToNative + KCopyFunctions;
const TInt KOffsetToOtherModes = KOffsetTo256 + KCopyFunctions;
const TInt KOffsetTo90Functions = 1;
const TInt KOffsetTo180Functions = 2;
if(iSourceMode == DisplayMode())
function = KOffsetToNative; //0
else if(iSourceMode == EColor256)
function = KOffsetTo256; //4
else
function = KOffsetToOtherModes; //8
if(iStateFlags & EOrientation90)
function += KOffsetTo90Functions; // + 1
if(iStateFlags & EOrientation180)
function += KOffsetTo180Functions; //+ 2
iCopyFunction = iCFTable[function];
Wipe();
}
inline void Rotate(TRect& aRect)
{
const TInt dx = aRect.iBr.iX - aRect.iTl.iX;
const TInt dy = aRect.iBr.iY - aRect.iTl.iY;
aRect.iBr.iX = aRect.iTl.iX + dy;
aRect.iBr.iY = aRect.iTl.iY + dx;
const TInt tmp = aRect.iTl.iX;
aRect.iTl.iX = aRect.iTl.iY;
aRect.iTl.iY = tmp;
}
/*
int bar = 0;
*/
TBool CDsa::AddUpdateRect(const TUint8* aBits, const TRect& aUpdateRect, const TRect& aRect)
{
if(iStateFlags & EOrientationChanged)
{
iStateFlags &= ~EOrientationFlags;
iStateFlags |= iNewFlags;
SetCopyFunction();
iStateFlags &= ~EOrientationChanged;
EpocSdlEnv::WaitDeviceChange();
return EFalse; //skip this frame as data is may be changed
}
if(iTargetAddr == NULL)
{
iTargetAddr = LockHwSurface();
}
TUint8* target = iTargetAddr;
if(target == NULL)
return EFalse;
TRect targetRect = TRect(TPoint(0, 0), SwSize());
TRect sourceRect = aRect;
TRect updateRect = aUpdateRect;
// TPoint move(0, 0);
if(iStateFlags & EOrientation90)
{
Rotate(sourceRect);
Rotate(updateRect);
}
if(iSourceMode != DisplayMode() || targetRect != sourceRect || targetRect != updateRect || ((iStateFlags & EOrientationFlags) != 0))
{
sourceRect.Intersection(targetRect); //so source always smaller or equal than target
//updateRect.Intersection(targetRect);
ClipCopy(target, aBits, updateRect, sourceRect);
}
else
{
const TInt byteCount = aRect.Width() * aRect.Height() * iSourceBpp; //this could be stored
Mem::Copy(target, aBits, byteCount);
}
return ETrue;
}
void CDsa::UpdateSwSurface()
{
iTargetAddr = NULL;
UnlockHwSurface(); //could be faster if does not use AO, but only check status before redraw, then no context switch needed
}
void CDsa::DoStop()
{
if(IsDsaAvailable())
iStateFlags |= ESdlThreadExplicitStop;
Stop();
}
void CDsa::Stop()
{
iStateFlags &= ~ERunning;
}
void CDsa::Start()
{
iStateFlags |= ERunning;
iStateFlags &= ~ESdlThreadExplicitStop;
if(iStateFlags & ESdlThreadSuspend)
{
EpocSdlEnv::Resume();
iStateFlags &= ~ ESdlThreadSuspend;
}
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventWindowReserved);
}
TBool CDsa::Blitter(CFbsBitmap& aBmp)
{
return iBlitter && iBlitter->BitBlt(Gc(), aBmp, HwRect(), SwSize());
}
void CDsa::SetBlitter(MBlitter* aBlitter)
{
iBlitter = aBlitter;
}
TPoint CDsa::WindowCoordinates(const TPoint& aPoint) const
{
TPoint pos = aPoint - iScreenRect.iTl;
const TSize asz = iScreenRect.Size();
if(iStateFlags & EOrientation180)
{
pos.iX = asz.iWidth - pos.iX;
pos.iY = asz.iHeight - pos.iY;
}
if(iStateFlags & EOrientation90)
{
pos.iX = aPoint.iY;
pos.iY = aPoint.iX;
}
pos.iX <<= 16;
pos.iY <<= 16;
pos.iX /= asz.iWidth;
pos.iY /= asz.iHeight;
pos.iX *= iSwSize.iWidth;
pos.iY *= iSwSize.iHeight;
pos.iX >>= 16;
pos.iY >>= 16;
return pos;
}
void CDsa::SetTargetRect()
{
iTargetRect = iScreenRect;
if(iStateFlags & EResizeRequest && EpocSdlEnv::Flags(CSDL::EAllowImageResizeKeepRatio))
{
const TSize asz = iScreenRect.Size();
const TSize sz = iSwSize;
TRect rect;
const TInt dh = (sz.iHeight << 16) / sz.iWidth;
if((asz.iWidth * dh ) >> 16 <= asz.iHeight)
{
rect.SetRect(TPoint(0, 0), TSize(asz.iWidth, (asz.iWidth * dh) >> 16));
}
else
{
const TInt dw = (sz.iWidth << 16) / sz.iHeight;
rect.SetRect(TPoint(0, 0), TSize((asz.iHeight * dw) >> 16, asz.iHeight));
}
rect.Move((asz.iWidth - rect.Size().iWidth) >> 1, (asz.iHeight - rect.Size().iHeight) >> 1);
iTargetRect = rect;
iTargetRect.Move(iScreenRect.iTl);
}
if(!(iStateFlags & EResizeRequest))
iSwSize = iScreenRect.Size();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CDsa::Copy256(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint8* source = aSource;
while(target < endt)
{
*target++ = aDsa.iLut256[*source++];
}
}
void CDsa::Copy256Reversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint8* source = aSource;
while(target < endt)
{
*(--endt) = aDsa.iLut256[*source++];
}
}
void CDsa::Copy256Flip(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint8* column = aSource;
while(target < endt)
{
*target++ = aDsa.iLut256[*column];
column += aLineLen;
}
}
void CDsa::Copy256FlipReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint8* column = aSource;
while(target < endt)
{
*(--endt) = aDsa.iLut256[*column];
column += aLineLen;
}
}
void CDsa::CopyMem(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* src = reinterpret_cast<const TUint32*>(aSource);
Mem::Copy(aTarget, src, aBytes << 2);
}
void CDsa::CopyMemFlip(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint32* column = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*target++ = *column;
column += aLineLen;
}
}
void CDsa::CopyMemReversed(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint32* source = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*(--endt) = *source++;
}
}
void CDsa::CopyMemFlipReversed(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint32* column = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*(--endt) = *column;
column += aLineLen;
}
}
/*
LOCAL_C TRgb rgb16MA(TInt aValue)
{
return TRgb::Color16MA(aValue);
}
*/
NONSHARABLE_CLASS(MRgbCopy)
{
public:
virtual void Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed) = 0;
virtual void FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed) = 0;
};
template <class T>
NONSHARABLE_CLASS(TRgbCopy) : public MRgbCopy
{
public:
TRgbCopy(TDisplayMode aMode);
void* operator new(TUint aBytes, TAny* aMem);
void Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed);
void FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed);
static TUint32 Gray256(const TUint8& aPixel);
static TUint32 Color256(const TUint8& aPixel);
static TUint32 Color4K(const TUint16& aPixel);
static TUint32 Color64K(const TUint16& aPixel);
static TUint32 Color16M(const TUint32& aPixel);
static TUint32 Color16MU(const TUint32& aPixel);
static TUint32 Color16MA(const TUint32& aPixel);
private:
typedef TUint32 (*TRgbFunc) (const T& aValue);
TRgbFunc iFunc;
};
template <class T>
void* TRgbCopy<T>::operator new(TUint /*aBytes*/, TAny* aMem)
{
return aMem;
}
template <class T>
TRgbCopy<T>::TRgbCopy(TDisplayMode aMode)
{
switch(aMode)
{
case EGray256 : iFunc = (TRgbFunc) Gray256; break;
case EColor256 : iFunc = (TRgbFunc) Color256; break;
case EColor4K : iFunc = (TRgbFunc) Color4K; break;
case EColor64K : iFunc = (TRgbFunc) Color64K; break;
case EColor16M : iFunc = (TRgbFunc) Color16M; break;
case EColor16MU : iFunc = (TRgbFunc) Color16MU; break;
case EColor16MA : iFunc = (TRgbFunc) Color16MA; break;
default:
PANIC(KErrNotSupported);
}
}
template <class T>
void TRgbCopy<T>::Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed)
{
const T* source = reinterpret_cast<const T*>(aSource);
TUint32* target = aTarget;
TUint32* endt = target + aBytes;
if(aReversed)
{
while(target < endt)
{
const T value = *source++;
*(--endt) = iFunc(value);//iFunc(value).Value();
}
}
else
{
while(target < endt)
{
const T value = *source++;
*target++ = iFunc(value);//iFunc(value).Value();
}
}
}
template <class T>
void TRgbCopy<T>::FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed)
{
const T* column = reinterpret_cast<const T*>(aSource);
TUint32* target = aTarget;
TUint32* endt = target + aBytes;
if(aReversed)
{
while(target < endt)
{
*(--endt) = iFunc(*column);
column += aLineLen;
}
}
else
{
while(target < endt)
{
*target++ = iFunc(*column);
column += aLineLen;
}
}
}
template <class T> TUint32 TRgbCopy<T>::Gray256(const TUint8& aPixel)
{
const TUint32 px = aPixel << 16 | aPixel << 8 | aPixel;
return px;
}
template <class T> TUint32 TRgbCopy<T>::Color256(const TUint8& aPixel)
{
return TRgb::Color256(aPixel).Value();
}
template <class T> TUint32 TRgbCopy<T>::Color4K(const TUint16& aPixel)
{
TUint32 col = (aPixel & 0xF00) << 12;
col |= (aPixel & 0xF00) << 8;
col |= (aPixel & 0x0F0) << 8;
col |= (aPixel & 0x0F0);
col |= (aPixel & 0x00F) << 4;
col |= (aPixel & 0x00F);
return col;
}
template <class T> TUint32 TRgbCopy<T>::Color64K(const TUint16& aPixel)
{
TUint32 col = (aPixel & 0xF800)<< 8;
col |= (aPixel & 0xE000) << 3;
col |= (aPixel & 0x07E0) << 5;
col |= (aPixel & 0xC0) >> 1;
col |= (aPixel & 0x07E0) << 3;
col |= (aPixel & 0x1C) >> 2;
return col;
}
template <class T> TUint32 TRgbCopy<T>::Color16M(const TUint32& aPixel)
{
return TRgb::Color16M(aPixel).Value();
}
template <class T> TUint32 TRgbCopy<T>::Color16MU(const TUint32& aPixel)
{
return TRgb::Color16MU(aPixel).Value();
}
template <class T> TUint32 TRgbCopy<T>::Color16MA(const TUint32& aPixel)
{
return TRgb::Color16MA(aPixel).Value();
}
typedef TUint64 TStackMem;
LOCAL_C MRgbCopy* GetCopy(TAny* mem, TDisplayMode aMode)
{
if(aMode == EColor256 || aMode == EGray256)
{
return new (mem) TRgbCopy<TUint8>(aMode);
}
if(aMode == EColor4K || aMode == EColor64K)
{
return new (mem) TRgbCopy<TUint16>(aMode);
}
if(aMode == EColor16M || aMode == EColor16MU || aMode == EColor16MA)
{
return new (mem) TRgbCopy<TUint32>(aMode);
}
PANIC(KErrNotSupported);
return NULL;
}
void CDsa::CopySlowFlipReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->FlipCopy(aTarget, aSource, aBytes, aLineLen, ETrue);
}
void CDsa::CopySlowFlip(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->FlipCopy(aTarget, aSource, aBytes, aLineLen, EFalse);
}
void CDsa::CopySlow(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->Copy(aTarget, aSource, aBytes, EFalse);
}
void CDsa::CopySlowReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->Copy(aTarget, aSource, aBytes, ETrue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////7
#include "dsa.h"
#include "sdlepocapi.h"
#include <cdsb.h>
LOCAL_C TInt BytesPerPixel(TDisplayMode aMode)
{
return ((TDisplayModeUtils::NumDisplayModeBitsPerPixel(aMode) - 1) >> 3) + 1;
}
NONSHARABLE_CLASS(TDsa)
{
public:
inline TDsa(const CDsa& aDsa);
inline TBool IsFlip() const;
inline TBool IsTurn() const;
inline const TSize& SwSize() const;
inline void Copy(TUint32* aTarget, const TUint8* aSrc, TInt aBytes, TInt aHeight) const;
private:
const CDsa& iDsa;
};
inline TDsa::TDsa(const CDsa& aDsa) : iDsa(aDsa)
{
}
inline TBool TDsa::IsTurn() const
{
return iDsa.iStateFlags & CDsa::EOrientation90;
}
inline TBool TDsa::IsFlip() const
{
return iDsa.iStateFlags & CDsa::EOrientation180;
}
inline const TSize& TDsa::SwSize() const
{
return iDsa.SwSize();
}
inline void TDsa::Copy(TUint32* aTarget, const TUint8* aSrc, TInt aBytes, TInt aHeight) const
{
iDsa.iCopyFunction(iDsa, aTarget, aSrc, aBytes, aHeight);
}
template<class T, class S>
void ClipCopy(const TDsa& iDsa, TUint8* aTarget,
const TUint8* aSource,
const TRect& aUpdateRect,
const TRect& aSourceRect)
{
const S* source = reinterpret_cast<const S*>(aSource);
const TInt lineWidth = aSourceRect.Width();
source += (aUpdateRect.iTl.iY * lineWidth);
const TInt sourceStartOffset = aUpdateRect.iTl.iX;
source += sourceStartOffset;
T* targetPtr = reinterpret_cast<T*>(aTarget);
const TInt scanLineWidth = iDsa.SwSize().iWidth;
targetPtr += (aSourceRect.iTl.iY + aUpdateRect.iTl.iY ) * scanLineWidth;
const TInt targetStartOffset = (aUpdateRect.iTl.iX + aSourceRect.iTl.iX);
targetPtr += targetStartOffset;
const TInt height = aUpdateRect.Height();
const TInt lineMove = iDsa.IsTurn() ? 1 : lineWidth;
const TInt copyLen = aUpdateRect.Width();
if(iDsa.IsFlip())
{
targetPtr += scanLineWidth * (height - 1);
for(TInt i = 0; i < height; i++) //source is always smaller
{
iDsa.Copy(reinterpret_cast<TUint32*>(targetPtr), reinterpret_cast<const TUint8*>(source), copyLen, height);
source += lineMove;
targetPtr -= scanLineWidth;
}
}
else
{
for(TInt i = 0; i < height; i++) //source is always smaller
{
iDsa.Copy(reinterpret_cast<TUint32*>(targetPtr), reinterpret_cast<const TUint8*>(source), copyLen, height);
source += lineMove;
targetPtr += scanLineWidth; // >> 2;
}
}
}
NONSHARABLE_CLASS(CDsaA) : public CDsa
{
public:
CDsaA(RWsSession& aSession);
private:
~CDsaA();
TUint8* LockSurface();
void UnlockHWSurfaceRequestComplete();
void UnlockHwSurface();
void CreateSurfaceL();
void Wipe(TInt aLength);
void Free();
void Update(CFbsBitmap& aBmp);
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
TInt ExternalUpdate();
// void ExternalUpdate();
protected:
CFbsBitmap* iBmp;
CFbsBitmap* iCopyBmp;
};
CDsaA::CDsaA(RWsSession& aSession) : CDsa(aSession)
{
}
void CDsaA::Free()
{
delete iBmp;
iBmp = NULL;
}
CDsaA::~CDsaA()
{
__ASSERT_DEBUG(iBmp == NULL, PANIC(KErrNotReady));
delete iCopyBmp;
}
TUint8* CDsaA::LockSurface()
{
iBmp->LockHeap();
return reinterpret_cast<TUint8*>(iBmp->DataAddress());
}
void CDsaA::UnlockHWSurfaceRequestComplete()
{
PANIC(KErrNotSupported);
}
void CDsaA::UnlockHwSurface()
{
iBmp->UnlockHeap();
SetUpdating(EFalse);
Update(*iBmp);
}
void CDsaA::Update(CFbsBitmap& aBmp)
{
if(!Blitter(aBmp))
{
if(SwSize() == HwRect().Size())
Dsa().Gc()->BitBlt(HwRect().iTl, &aBmp);
else
Dsa().Gc()->DrawBitmap(HwRect(), &aBmp);
}
DrawOverlays();
Dsa().ScreenDevice()->Update();
}
void CDsaA::CreateSurfaceL()
{
delete iBmp;
iBmp = NULL;
iBmp = new (ELeave) CFbsBitmap();
User::LeaveIfError(iBmp->Create(SwSize(), DisplayMode()));
}
void CDsaA::Wipe(TInt aLength) //dont call in drawing
{
iBmp->LockHeap();
Mem::FillZ(iBmp->DataAddress(), aLength);
iBmp->UnlockHeap();
}
TInt CDsaA::ExternalUpdate()
{
if(iCopyBmp->Handle() == 0)
{
const TInt err = iCopyBmp->Duplicate(iBmp->Handle());
if(err != KErrNone)
return err;
}
Update(*iCopyBmp);
return KErrNone;
}
void CDsaA::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
iCopyBmp = new (ELeave) CFbsBitmap();
CDsa::ConstructL(aWindow, aDevice);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(MDsbObs)
{
public:
virtual void SurfaceReady() = 0;
virtual CDirectScreenBitmap& Dsb() = 0;
};
NONSHARABLE_CLASS(CDsbSurface) : public CActive
{
public:
CDsbSurface(MDsbObs& aDsb);
TUint8* Address();
void Complete();
~CDsbSurface();
private:
void RunL();
void DoCancel();
private:
MDsbObs& iDsb;
TUint8* iAddress;
};
CDsbSurface::CDsbSurface(MDsbObs& aDsb) : CActive(CActive::EPriorityHigh) , iDsb(aDsb)
{
CActiveScheduler::Add(this);
}
CDsbSurface::~CDsbSurface()
{
Cancel();
}
void CDsbSurface::Complete()
{
if(iAddress != NULL && !IsActive())
{
iAddress = NULL;
SetActive();
iDsb.Dsb().EndUpdate(iStatus);
}
}
TUint8* CDsbSurface::Address()
{
if(iAddress == NULL && !IsActive())
{
TAcceleratedBitmapInfo info;
if(KErrNone == iDsb.Dsb().BeginUpdate(info))
iAddress = info.iAddress;
}
return iAddress;
}
void CDsbSurface::RunL()
{
iDsb.SurfaceReady();
}
void CDsbSurface::DoCancel()
{
//empty
}
NONSHARABLE_CLASS(CDsaB) : public CDsa, public MDsbObs
{
public:
CDsaB(RWsSession& aSession, TInt aFlags);
private:
~CDsaB();
TUint8* LockSurface();
void UnlockHWSurfaceRequestComplete();
void UnlockHwSurface();
void CreateSurfaceL();
void Wipe(TInt aLength);
void RecreateL();
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
CDirectScreenBitmap& Dsb();
void SurfaceReady();
TInt ExternalUpdate();
private:
CDsbSurface* iSurface1;
CDsbSurface* iSurface2;
CDirectScreenBitmap* iDsb;
TInt iType;
};
CDsaB::CDsaB(RWsSession& aSession, TInt aFlags) : CDsa(aSession), iType(aFlags)
{
}
void CDsaB::UnlockHWSurfaceRequestComplete()
{
iSurface1->Complete();
if(iSurface2 != NULL)
iSurface2->Complete();
}
void CDsaB::CreateSurfaceL()
{
__ASSERT_ALWAYS(SwSize() == HwRect().Size(), PANIC(KErrNotSupported));
}
void CDsaB::Wipe(TInt aLength) //dont call in drawing
{
TUint8* addr = LockSurface();
if(addr != NULL)
{
Mem::FillZ(addr, aLength);
UnlockHwSurface();
}
}
void CDsaB::UnlockHwSurface()
{
EpocSdlEnv::Request(CDsa::ERequestUpdate);
}
TUint8* CDsaB::LockSurface()
{
TUint8* addr = iSurface1->Address();
if(addr == NULL && iSurface2 != NULL)
addr = iSurface2->Address();
SetUpdating(addr == NULL);
return addr;
}
void CDsaB::SurfaceReady()
{
SetUpdating(EFalse);
}
CDirectScreenBitmap& CDsaB::Dsb()
{
return *iDsb;
}
void CDsaB::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
if(iDsb == NULL)
iDsb = CDirectScreenBitmap::NewL();
CDsa::ConstructL(aWindow, aDevice);
if(iSurface1 == NULL)
iSurface1 = new (ELeave) CDsbSurface(*this);
if(iSurface2 == NULL && iType & CDirectScreenBitmap::EDoubleBuffer)
iSurface2 = new (ELeave) CDsbSurface(*this);
}
CDsaB::~CDsaB()
{
delete iSurface1;
delete iSurface2;
delete iDsb;
}
void CDsaB::RecreateL()
{
iDsb->Close();
iDsb->Create(HwRect(), CDirectScreenBitmap::TSettingsFlags(iType));
}
TInt CDsaB::ExternalUpdate()
{
if(LockSurface())
{
UnlockHWSurfaceRequestComplete();
return KErrNone;
}
return KErrNotReady;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
CDsa* CDsa::CreateL(RWsSession& aSession)
{
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSB))
{
TInt flags = CDirectScreenBitmap::ENone;
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSBDoubleBuffer))
flags |= CDirectScreenBitmap::EDoubleBuffer;
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSBIncrentalUpdate))
flags |= CDirectScreenBitmap::EIncrementalUpdate;
return new (ELeave) CDsaB(aSession, flags);
}
else
return new (ELeave) CDsaA(aSession);
}
void CDsa::RecreateL()
{
}
void CDsa::Free()
{
}
TSize CDsa::WindowSize() const
{
TSize size = iSwSize;
if(iStateFlags & EOrientation90)
{
const TInt tmp = size.iWidth;
size.iWidth = size.iHeight;
size.iHeight = tmp;
}
return size;
}
void CDsa::SetSuspend()
{
iStateFlags |= ESdlThreadSuspend;
}
void CDsa::ReleaseStop()
{
iStateFlags &= ~ESdlThreadExplicitStop;
}
TBool CDsa::Stopped() const
{
return (iStateFlags & ESdlThreadExplicitStop);
}
void CDsa::SetOrientation(CSDL::TOrientationMode aOrientation)
{
TInt flags = 0;
switch(aOrientation)
{
case CSDL::EOrientation90:
flags = EOrientation90;
break;
case CSDL::EOrientation180:
flags = EOrientation180;
break;
case CSDL::EOrientation270:
flags = EOrientation90 | EOrientation180;
break;
case CSDL::EOrientation0:
flags = 0;
break;
}
if(flags != (iStateFlags & EOrientationFlags))
{
iStateFlags |= EOrientationChanged;
iNewFlags = flags; //cannot be set during drawing...
}
}
CDsa::~CDsa()
{
if(iDsa != NULL)
{
iDsa->Cancel();
}
iOverlays.Close();
delete iDsa;
User::Free(iLut256);
}
void CDsa::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
if(iDsa != NULL)
{
iDsa->Cancel();
delete iDsa;
iDsa = NULL;
}
iDsa = CDirectScreenAccess::NewL(
iSession,
aDevice,
aWindow,
*this);
if(iLut256 == NULL)
iLut256 = (TUint32*) User::AllocL(256 * sizeof(TUint32));
iTargetMode = aWindow.DisplayMode();
iTargetBpp = BytesPerPixel(DisplayMode());
iScreenRect = TRect(aWindow.Position(), aWindow.Size());
SetTargetRect();
RestartL();
}
void CDsa::DrawOverlays()
{
const TInt last = iOverlays.Count() - 1;
for(TInt i = last; i >= 0 ; i--)
iOverlays[i].iOverlay->Draw(*iDsa->Gc(), HwRect(), SwSize());
}
TInt CDsa::AppendOverlay(MOverlay& aOverlay, TInt aPriority)
{
TInt i;
for(i = 0; i < iOverlays.Count() && iOverlays[i].iPriority < aPriority; i++)
{}
const TOverlay overlay = {&aOverlay, aPriority};
return iOverlays.Insert(overlay, i);
}
TInt CDsa::RemoveOverlay(MOverlay& aOverlay)
{
for(TInt i = 0; i < iOverlays.Count(); i++)
{
if(iOverlays[i].iOverlay == &aOverlay)
{
iOverlays.Remove(i);
return KErrNone;
}
}
return KErrNotFound;
}
void CDsa::LockPalette(TBool aLock)
{
if(aLock)
iStateFlags |= EPaletteLocked;
else
iStateFlags &= ~EPaletteLocked;
}
TInt CDsa::SetPalette(TInt aFirst, TInt aCount, TUint32* aPalette)
{
if(iLut256 == NULL)
return KErrNotFound;
const TInt count = aCount - aFirst;
if(count > 256)
return KErrArgument;
if(iStateFlags & EPaletteLocked)
return KErrNone;
for(TInt i = aFirst; i < count; i++) //not so busy here:-)
{
iLut256[i] = aPalette[i];
}
return KErrNone;
}
void CDsa::RestartL()
{
//const TBool active = iDsa->IsActive();
//if(!active)
iDsa->StartL();
const RRegion* r = iDsa->DrawingRegion();
const TRect rect = r->BoundingRect();
iDsa->Gc()->SetClippingRegion(r);
if(rect != iScreenRect)
{
// iDsa->Cancel();
return ;
}
//iScreenRect = rect; //to ensure properly set, albeit may not(?) match to value SDL has - therefore may has to clip
//targetrect shall no change
SetTargetRect();
RecreateL();
iStateFlags |= ERunning;
ReleaseStop();
if(iStateFlags & ESdlThreadSuspend)
{
EpocSdlEnv::Resume();
iStateFlags &= ~ ESdlThreadSuspend;
}
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventWindowReserved);
}
CDsa::CDsa(RWsSession& aSession) :
iSession(aSession),
iStateFlags(0)
{
// CActiveScheduler::Add(this);
iCFTable[0] = CopyMem;
iCFTable[1] = CopyMemFlipReversed;
iCFTable[2] = CopyMemReversed;
iCFTable[3] = CopyMemFlip;
iCFTable[4] = Copy256;
iCFTable[5] = Copy256FlipReversed;
iCFTable[6] = Copy256Reversed;
iCFTable[7] = Copy256Flip;
iCFTable[8] = CopySlow;
iCFTable[9] = CopySlowFlipReversed;
iCFTable[10] = CopySlowReversed;
iCFTable[11] = CopySlowFlip;
}
RWsSession& CDsa::Session()
{
return iSession;
}
TInt CDsa::RedrawRequest()
{
if(!(iStateFlags & (EUpdating) && (iStateFlags & ERunning)))
{
return ExternalUpdate();
}
return KErrNotReady;
}
TUint8* CDsa::LockHwSurface()
{
if((iStateFlags & EUpdating) == 0) //else frame is skipped
{
return LockSurface();
}
return NULL;
}
/*
void CDsa::RunL()
{
iStateFlags &= ~EUpdating;
}
void CDsa::DoCancel()
{
iStateFlags &= ~EUpdating;
//nothing can do, just wait?
}
*/
TInt CDsa::AllocSurface(TBool aHwSurface, const TSize& aSize, TDisplayMode aMode)
{
if(aHwSurface && aMode != DisplayMode())
return KErrArgument;
iSourceMode = aMode;
iSourceBpp = BytesPerPixel(aMode);
const TSize size = WindowSize();
if(aSize.iWidth > size.iWidth)
return KErrTooBig;
if(aSize.iHeight > size.iHeight)
return KErrTooBig;
TRAPD(err, CreateSurfaceL());
if(err != KErrNone)
return err;
SetCopyFunction();
return KErrNone;
}
void CDsa::CreateZoomerL(const TSize& aSize)
{
iSwSize = aSize;
iStateFlags |= EResizeRequest;
CreateSurfaceL();
SetTargetRect();
}
/*
void SaveBmp(const TDesC& aName, const TAny* aData, TInt aLength, const TSize& aSz, TDisplayMode aMode)
{
CFbsBitmap* s = new CFbsBitmap();
s->Create(aSz, aMode);
s->LockHeap();
TUint32* addr = s->DataAddress();
Mem::Copy(addr, aData, aLength);
s->UnlockHeap();
s->Save(aName);
s->Reset();
delete s;
}
void SaveBmp(const TDesC& aName, const TUint32* aData, const TSize& aSz)
{
CFbsBitmap* s = new CFbsBitmap();
s->Create(aSz, EColor64K);
TBitmapUtil bmp(s);
bmp.Begin(TPoint(0, 0));
for(TInt j = 0; j < aSz.iHeight; j++)
{
bmp.SetPos(TPoint(0, j));
for(TInt i = 0; i < aSz.iWidth; i++)
{
bmp.SetPixel(*aData);
aData++;
bmp.IncXPos();
}
}
bmp.End();
s->Save(aName);
s->Reset();
delete s;
}
TBuf<16> FooName(TInt aFoo)
{
TBuf<16> b;
b.Format(_L("C:\\pic%d.mbm"), aFoo);
return b;
}
void ClipCopy(TUint8* aTarget, const TUint8* aSource, const TRect& aRect, const TPoint& aTargetPos)
{
const TInt iSourceBpp = 1;
const TInt iTargetBpp = 4;
const TInt iScanLineWidth = 800;
TUint8* target = aTarget;
const TUint8* source = aSource;
const TInt lineWidth = aRect.Width();
source += iSourceBpp * (aRect.iTl.iY * lineWidth);
const TInt sourceStartOffset = iSourceBpp * aRect.iTl.iX;
source += sourceStartOffset;
target += iTargetBpp * ((aTargetPos.iY + aRect.iTl.iY ) * lineWidth);
const TInt targetStartOffset = iTargetBpp * (aRect.iTl.iX + aTargetPos.iX);
target += targetStartOffset;
TUint32* targetPtr = reinterpret_cast<TUint32*>(target);
const TInt targetWidth = iScanLineWidth >> 2;
const TInt height = aRect.Height();
}
*/
/*
void CDsa::ClipCopy(TUint8* aTarget,
const TUint8* aSource,
const TRect& aUpdateRect,
const TRect& aSourceRect) const
{
//TUint8* target = aTarget;
const TUint32* source = (const TUint32*) aSource;
const TInt lineWidth = aSourceRect.Width();
source += (aUpdateRect.iTl.iY * lineWidth);
const TInt sourceStartOffset = aUpdateRect.iTl.iX;
source += sourceStartOffset;
TUint32* targetPtr = reinterpret_cast<TUint32*>(aTarget);
targetPtr += (aSourceRect.iTl.iY + aUpdateRect.iTl.iY ) * SwSize().iWidth;
const TInt targetStartOffset = (aUpdateRect.iTl.iX + aSourceRect.iTl.iX);
targetPtr += targetStartOffset;
// TUint32* targetPtr = reinterpret_cast<TUint32*>(target);
const TInt targetWidth32 = SwSize().iWidth;
const TInt height = aUpdateRect.Height();
const TInt lineMove = iStateFlags & EOrientation90 ? 1 : lineWidth;
const TInt copyLen = aUpdateRect.Width();
if(iStateFlags & EOrientation180)
{
targetPtr += targetWidth32 * (height - 1);
for(TInt i = 0; i < height; i++) //source is always smaller
{
iCopyFunction(*this, targetPtr, (TUint8*)source, copyLen, height);
source += lineMove;
targetPtr -= targetWidth32;
}
}
else
{
for(TInt i = 0; i < height; i++) //source is always smaller
{
iCopyFunction(*this, targetPtr, (TUint8*)source, copyLen, height);
source += lineMove;
targetPtr += targetWidth32; // >> 2;
}
}
}
*/
void CDsa::ClipCopy(TUint8* aTarget, const TUint8* aSource, const TRect& aRect, const TPoint& aTargetPos) const
{
TUint8* target = aTarget;
const TUint8* source = aSource;
const TInt lineWidth = aRect.Width();
source += iSourceBpp * (aRect.iTl.iY * lineWidth);
TInt sourceStartOffset = iSourceBpp * aRect.iTl.iX;
source += sourceStartOffset;
target += iTargetBpp * ((aTargetPos.iY + aRect.iTl.iY ) * lineWidth);
TInt targetStartOffset = iTargetBpp * (aRect.iTl.iX + aTargetPos.iX);
target += targetStartOffset;
TUint32* targetPtr = reinterpret_cast<TUint32*>(target);
const TInt targetWidth = iScanLineWidth >> 2;
const TInt height = aRect.Height();
TInt lineMove = iStateFlags & EOrientation90 ? 1 : lineWidth;
if(iStateFlags & EOrientation180)
{
targetPtr += targetWidth * (height - 1);
for(TInt i = 0; i < height; i++) //source is always smaller
{
iCopyFunction(*this, targetPtr, source, lineWidth, height);
source += lineMove;
targetPtr -= targetWidth;
}
}
else
{
for(TInt i = 0; i < height; i++) //source is always smaller
{
iCopyFunction(*this, targetPtr, source, lineWidth, height);
source += lineMove;
targetPtr += targetWidth;
}
}
}
/*
void CDsa::ClipCopy(TUint8* aTarget,
const TUint8* aSource,
const TRect& aUpdateRect,
const TRect& aSourceRect) const
{
const TDsa dsa(*this);
switch(iSourceBpp)
{
case 1:
::ClipCopy<TUint32, TUint8>(dsa, aTarget, aSource, aUpdateRect, aSourceRect);
break;
case 2:
::ClipCopy<TUint32, TUint16>(dsa, aTarget, aSource, aUpdateRect, aSourceRect);
break;
case 4:
::ClipCopy<TUint32, TUint32>(dsa, aTarget, aSource, aUpdateRect, aSourceRect);
break;
}
}
*/
void CDsa::Wipe() //dont call in drawing
{
if(IsDsaAvailable())
Wipe(iTargetBpp * SwSize().iWidth * SwSize().iHeight);
}
void CDsa::SetCopyFunction()
{
//calculate offset to correct function in iCFTable according to given parameters
TInt function = 0;
const TInt KCopyFunctions = 4;
const TInt KOffsetToNative = 0;
const TInt KOffsetTo256 = KOffsetToNative + KCopyFunctions;
const TInt KOffsetToOtherModes = KOffsetTo256 + KCopyFunctions;
const TInt KOffsetTo90Functions = 1;
const TInt KOffsetTo180Functions = 2;
if(iSourceMode == DisplayMode())
function = KOffsetToNative; //0
else if(iSourceMode == EColor256)
function = KOffsetTo256; //4
else
function = KOffsetToOtherModes; //8
if(iStateFlags & EOrientation90)
function += KOffsetTo90Functions; // + 1
if(iStateFlags & EOrientation180)
function += KOffsetTo180Functions; //+ 2
iCopyFunction = iCFTable[function];
Wipe();
}
inline void Rotate(TRect& aRect)
{
const TInt dx = aRect.iBr.iX - aRect.iTl.iX;
const TInt dy = aRect.iBr.iY - aRect.iTl.iY;
aRect.iBr.iX = aRect.iTl.iX + dy;
aRect.iBr.iY = aRect.iTl.iY + dx;
const TInt tmp = aRect.iTl.iX;
aRect.iTl.iX = aRect.iTl.iY;
aRect.iTl.iY = tmp;
}
/*
int bar = 0;
*/
/*
TBool CDsa::AddUpdateRect(const TUint8* aBits, const TRect& aUpdateRect, const TRect& aRect)
{
if(iStateFlags & EOrientationChanged)
{
iStateFlags &= ~EOrientationFlags;
iStateFlags |= iNewFlags;
SetCopyFunction();
iStateFlags &= ~EOrientationChanged;
EpocSdlEnv::WaitDeviceChange();
return EFalse; //skip this frame as data is may be changed
}
if(iTargetAddr == NULL)
{
iTargetAddr = LockHwSurface();
}
TUint8* target = iTargetAddr;
if(target == NULL)
return EFalse;
TRect targetRect = TRect(TPoint(0, 0), SwSize());
TRect sourceRect = aRect;
TRect updateRect = aUpdateRect;
// TPoint move(0, 0);
if(iStateFlags & EOrientation90)
{
Rotate(sourceRect);
Rotate(updateRect);
}
if(iSourceMode != DisplayMode() || targetRect != sourceRect || targetRect != updateRect || ((iStateFlags & EOrientationFlags) != 0))
{
sourceRect.Intersection(targetRect); //so source always smaller or equal than target
//updateRect.Intersection(targetRect);
ClipCopy(target, aBits, updateRect, sourceRect);
}
else
{
const TInt byteCount = aRect.Width() * aRect.Height() * iSourceBpp; //this could be stored
Mem::Copy(target, aBits, byteCount);
}
return ETrue;
}
*/
TBool CDsa::AddUpdateRect(const TUint8* aBits, const TRect& aUpdateRect, const TRect& aRect)
{
if(iStateFlags & EOrientationChanged)
{
iStateFlags &= ~EOrientationFlags;
iStateFlags |= iNewFlags;
SetCopyFunction();
iStateFlags &= ~EOrientationChanged;
EpocSdlEnv::WaitDeviceChange();
return EFalse; //skip this frame as data is may be changed
}
if(iTargetAddr == NULL)
{
iTargetAddr = LockHwSurface();
}
TUint8* target = iTargetAddr;
if(target == NULL)
return EFalse;
TRect targetRect = Rect();
TRect sourceRect = aRect;
TRect updateRect = aUpdateRect;
if(iStateFlags & EOrientation90)
{
Rotate(sourceRect);
Rotate(updateRect);
}
if(iSourceMode != DisplayMode() || targetRect != sourceRect || targetRect != updateRect || ((iStateFlags & EOrientationFlags) != 0))
{
sourceRect.Intersection(targetRect); //so source always smaller or equal than target
updateRect.Intersection(targetRect);
ClipCopy(target, aBits, updateRect, sourceRect.iTl);
}
else
{
const TInt byteCount = aRect.Width() * aRect.Height() * iSourceBpp; //this could be stored
Mem::Copy(target, aBits, byteCount);
}
return ETrue;
}
void CDsa::UpdateSwSurface()
{
iTargetAddr = NULL;
UnlockHwSurface(); //could be faster if does not use AO, but only check status before redraw, then no context switch needed
}
void CDsa::Resume()
{
if(Stopped())
Restart(RDirectScreenAccess::ETerminateRegion);
}
void CDsa::DoStop()
{
if(IsDsaAvailable())
iStateFlags |= ESdlThreadExplicitStop;
Stop();
}
void CDsa::Stop()
{
iStateFlags &= ~ERunning;
// Cancel(); //can be called only from main!
iDsa->Cancel();
}
void CDsa::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/)
{
// iStateFlags |= EChangeNotify;
Stop();
}
void CDsa::Restart(RDirectScreenAccess::TTerminationReasons aReason)
{
if(aReason == RDirectScreenAccess::ETerminateRegion) //auto restart
{
TRAPD(err, RestartL());
PANIC_IF_ERROR(err);
}
}
void CDsa::SetBlitter(MBlitter* aBlitter)
{
iBlitter = aBlitter;
}
TPoint CDsa::WindowCoordinates(const TPoint& aPoint) const
{
TPoint pos = aPoint - iScreenRect.iTl;
const TSize asz = iScreenRect.Size();
if(iStateFlags & EOrientation180)
{
pos.iX = asz.iWidth - pos.iX;
pos.iY = asz.iHeight - pos.iY;
}
if(iStateFlags & EOrientation90)
{
pos.iX = aPoint.iY;
pos.iY = aPoint.iX;
}
pos.iX <<= 16;
pos.iY <<= 16;
pos.iX /= asz.iWidth;
pos.iY /= asz.iHeight;
pos.iX *= iSwSize.iWidth;
pos.iY *= iSwSize.iHeight;
pos.iX >>= 16;
pos.iY >>= 16;
return pos;
}
void CDsa::SetTargetRect()
{
iTargetRect = iScreenRect;
if(iStateFlags & EResizeRequest && EpocSdlEnv::Flags(CSDL::EAllowImageResizeKeepRatio))
{
const TSize asz = iScreenRect.Size();
const TSize sz = iSwSize;
TRect rect;
const TInt dh = (sz.iHeight << 16) / sz.iWidth;
if((asz.iWidth * dh ) >> 16 <= asz.iHeight)
{
rect.SetRect(TPoint(0, 0), TSize(asz.iWidth, (asz.iWidth * dh) >> 16));
}
else
{
const TInt dw = (sz.iWidth << 16) / sz.iHeight;
rect.SetRect(TPoint(0, 0), TSize((asz.iHeight * dw) >> 16, asz.iHeight));
}
rect.Move((asz.iWidth - rect.Size().iWidth) >> 1, (asz.iHeight - rect.Size().iHeight) >> 1);
iTargetRect = rect;
iTargetRect.Move(iScreenRect.iTl);
}
if(!(iStateFlags & EResizeRequest))
iSwSize = iScreenRect.Size();
// iScanLineWidth = /*iTargetBpp **/ SwSize().iWidth;
}
/*)
TBool CDsa::ChangeTrigger()
{
const TBool change = iStateFlags & EChangeNotify;
iStateFlags &= ~EChangeNotify;
return change;
}
*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CDsa::Copy256(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint8* source = aSource;
while(target < endt)
{
*target++ = aDsa.iLut256[*source++];
}
}
void CDsa::Copy256Reversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint8* source = aSource;
while(target < endt)
{
*(--endt) = aDsa.iLut256[*source++];
}
}
void CDsa::Copy256Flip(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint8* column = aSource;
while(target < endt)
{
*target++ = aDsa.iLut256[*column];
column += aLineLen;
}
}
void CDsa::Copy256FlipReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint8* column = aSource;
while(target < endt)
{
*(--endt) = aDsa.iLut256[*column];
column += aLineLen;
}
}
void CDsa::CopyMem(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* src = reinterpret_cast<const TUint32*>(aSource);
Mem::Copy(aTarget, src, aBytes << 2);
}
void CDsa::CopyMemFlip(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint32* column = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*target++ = *column;
column += aLineLen;
}
}
void CDsa::CopyMemReversed(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint32* source = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*(--endt) = *source++;
}
}
void CDsa::CopyMemFlipReversed(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint32* column = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*(--endt) = *column;
column += aLineLen;
}
}
/*
LOCAL_C TRgb rgb16MA(TInt aValue)
{
return TRgb::Color16MA(aValue);
}
*/
NONSHARABLE_CLASS(MRgbCopy)
{
public:
virtual void Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed) = 0;
virtual void FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed) = 0;
};
template <class T>
NONSHARABLE_CLASS(TRgbCopy) : public MRgbCopy
{
public:
TRgbCopy(TDisplayMode aMode);
void* operator new(TUint aBytes, TAny* aMem);
void Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed);
void FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed);
static TUint32 Gray256(const TUint8& aPixel);
static TUint32 Color256(const TUint8& aPixel);
static TUint32 Color4K(const TUint16& aPixel);
static TUint32 Color64K(const TUint16& aPixel);
static TUint32 Color16M(const TUint32& aPixel);
static TUint32 Color16MU(const TUint32& aPixel);
static TUint32 Color16MA(const TUint32& aPixel);
private:
typedef TUint32 (*TRgbFunc) (const T& aValue);
TRgbFunc iFunc;
};
template <class T>
void* TRgbCopy<T>::operator new(TUint /*aBytes*/, TAny* aMem)
{
return aMem;
}
template <class T>
TRgbCopy<T>::TRgbCopy(TDisplayMode aMode)
{
switch(aMode)
{
case EGray256 : iFunc = (TRgbFunc) Gray256; break;
case EColor256 : iFunc = (TRgbFunc) Color256; break;
case EColor4K : iFunc = (TRgbFunc) Color4K; break;
case EColor64K : iFunc = (TRgbFunc) Color64K; break;
case EColor16M : iFunc = (TRgbFunc) Color16M; break;
case EColor16MU : iFunc = (TRgbFunc) Color16MU; break;
case EColor16MA : iFunc = (TRgbFunc) Color16MA; break;
default:
PANIC(KErrNotSupported);
}
}
template <class T>
void TRgbCopy<T>::Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed)
{
const T* source = reinterpret_cast<const T*>(aSource);
TUint32* target = aTarget;
TUint32* endt = target + aBytes;
if(aReversed)
{
while(target < endt)
{
const T value = *source++;
*(--endt) = iFunc(value);//iFunc(value).Value();
}
}
else
{
while(target < endt)
{
const T value = *source++;
*target++ = iFunc(value);//iFunc(value).Value();
}
}
}
template <class T>
void TRgbCopy<T>::FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed)
{
const T* column = reinterpret_cast<const T*>(aSource);
TUint32* target = aTarget;
TUint32* endt = target + aBytes;
if(aReversed)
{
while(target < endt)
{
*(--endt) = iFunc(*column);
column += aLineLen;
}
}
else
{
while(target < endt)
{
*target++ = iFunc(*column);
column += aLineLen;
}
}
}
template <class T> TUint32 TRgbCopy<T>::Gray256(const TUint8& aPixel)
{
const TUint32 px = aPixel << 16 | aPixel << 8 | aPixel;
return px;
}
template <class T> TUint32 TRgbCopy<T>::Color256(const TUint8& aPixel)
{
return TRgb::Color256(aPixel).Value();
}
template <class T> TUint32 TRgbCopy<T>::Color4K(const TUint16& aPixel)
{
TUint32 col = (aPixel & 0xF00) << 12;
col |= (aPixel & 0xF00) << 8;
col |= (aPixel & 0x0F0) << 8;
col |= (aPixel & 0x0F0);
col |= (aPixel & 0x00F) << 4;
col |= (aPixel & 0x00F);
return col;
}
template <class T> TUint32 TRgbCopy<T>::Color64K(const TUint16& aPixel)
{
TUint32 col = (aPixel & 0xF800)<< 8;
col |= (aPixel & 0xE000) << 3;
col |= (aPixel & 0x07E0) << 5;
col |= (aPixel & 0xC0) >> 1;
col |= (aPixel & 0x07E0) << 3;
col |= (aPixel & 0x1C) >> 2;
return col;
}
template <class T> TUint32 TRgbCopy<T>::Color16M(const TUint32& aPixel)
{
return TRgb::Color16M(aPixel).Value();
}
template <class T> TUint32 TRgbCopy<T>::Color16MU(const TUint32& aPixel)
{
return TRgb::Color16MU(aPixel).Value();
}
template <class T> TUint32 TRgbCopy<T>::Color16MA(const TUint32& aPixel)
{
return TRgb::Color16MA(aPixel).Value();
}
typedef TUint64 TStackMem;
LOCAL_C MRgbCopy* GetCopy(TAny* mem, TDisplayMode aMode)
{
if(aMode == EColor256 || aMode == EGray256)
{
return new (mem) TRgbCopy<TUint8>(aMode);
}
if(aMode == EColor4K || aMode == EColor64K)
{
return new (mem) TRgbCopy<TUint16>(aMode);
}
if(aMode == EColor16M || aMode == EColor16MU || aMode == EColor16MA)
{
return new (mem) TRgbCopy<TUint32>(aMode);
}
PANIC(KErrNotSupported);
return NULL;
}
void CDsa::CopySlowFlipReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->FlipCopy(aTarget, aSource, aBytes, aLineLen, ETrue);
}
void CDsa::CopySlowFlip(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->FlipCopy(aTarget, aSource, aBytes, aLineLen, EFalse);
}
void CDsa::CopySlow(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->Copy(aTarget, aSource, aBytes, EFalse);
}
void CDsa::CopySlowReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->Copy(aTarget, aSource, aBytes, ETrue);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////7
#include "dsa.h"
#include "sdlepocapi.h"
#include <cdsb.h>
LOCAL_C TInt BytesPerPixel(TDisplayMode aMode)
{
return ((TDisplayModeUtils::NumDisplayModeBitsPerPixel(aMode) - 1) >> 3) + 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(CDsaA) : public CDsa
{
public:
CDsaA(RWsSession& aSession);
private:
~CDsaA();
TUint8* LockSurface();
void UnlockHWSurfaceRequestComplete();
void UnlockHwSurface();
void CreateSurfaceL();
void Wipe(TInt aLength);
void RecreateL();
void Free();
TInt ExternalUpdate() {return 0;}
private:
CFbsBitmap* iBmp;
};
CDsaA::CDsaA(RWsSession& aSession) : CDsa(aSession)
{
}
void CDsaA::Free()
{
delete iBmp;
iBmp = NULL;
}
CDsaA::~CDsaA()
{
__ASSERT_DEBUG(iBmp == NULL, PANIC(KErrNotReady));
}
TUint8* CDsaA::LockSurface()
{
iBmp->LockHeap();
return reinterpret_cast<TUint8*>(iBmp->DataAddress());
}
void CDsaA::UnlockHWSurfaceRequestComplete()
{
PANIC(KErrNotSupported);
}
void CDsaA::UnlockHwSurface()
{
iBmp->UnlockHeap();
SetUpdating(EFalse);
Dsa().Gc()->BitBlt(HwRect().iTl, iBmp);
Dsa().ScreenDevice()->Update();
}
void CDsaA::CreateSurfaceL()
{
delete iBmp;
iBmp = NULL;
iBmp = new (ELeave) CFbsBitmap();
User::LeaveIfError(iBmp->Create(HwRect().Size(), DisplayMode()));
}
void CDsaA::Wipe(TInt aLength) //dont call in drawing
{
iBmp->LockHeap();
Mem::FillZ(iBmp->DataAddress(), aLength);
iBmp->UnlockHeap();
}
void CDsaA::RecreateL()
{
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
NONSHARABLE_CLASS(MDsbObs)
{
public:
virtual void SurfaceReady() = 0;
virtual CDirectScreenBitmap& Dsb() = 0;
};
NONSHARABLE_CLASS(CDsbSurface) : public CActive
{
public:
CDsbSurface(MDsbObs& aDsb);
TUint8* Address();
void Complete();
~CDsbSurface();
private:
void RunL();
void DoCancel();
private:
MDsbObs& iDsb;
TUint8* iAddress;
};
CDsbSurface::CDsbSurface(MDsbObs& aDsb) : CActive(CActive::EPriorityHigh) , iDsb(aDsb)
{
CActiveScheduler::Add(this);
}
CDsbSurface::~CDsbSurface()
{
Cancel();
}
void CDsbSurface::Complete()
{
if(iAddress != NULL && !IsActive())
{
iAddress = NULL;
SetActive();
iDsb.Dsb().EndUpdate(iStatus);
}
}
TUint8* CDsbSurface::Address()
{
if(iAddress == NULL && !IsActive())
{
TAcceleratedBitmapInfo info;
if(KErrNone == iDsb.Dsb().BeginUpdate(info))
iAddress = info.iAddress;
}
return iAddress;
}
void CDsbSurface::RunL()
{
iDsb.SurfaceReady();
}
void CDsbSurface::DoCancel()
{
//empty
}
NONSHARABLE_CLASS(CDsaB) : public CDsa, public MDsbObs
{
public:
CDsaB(RWsSession& aSession);
private:
~CDsaB();
TUint8* LockSurface();
void UnlockHWSurfaceRequestComplete();
void UnlockHwSurface();
void CreateSurfaceL();
void Wipe(TInt aLength);
void RecreateL();
void ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice);
void Free();
CDirectScreenBitmap& Dsb();
void SurfaceReady();
TInt ExternalUpdate() {return 0;}
private:
CDsbSurface* iSurface1;
CDsbSurface* iSurface2;
CDirectScreenBitmap* iDsb;
};
CDsaB::CDsaB(RWsSession& aSession) : CDsa(aSession)
{
}
void CDsaB::Free()
{
}
void CDsaB::UnlockHWSurfaceRequestComplete()
{
iSurface1->Complete();
iSurface2->Complete();
}
void CDsaB::CreateSurfaceL()
{
}
void CDsaB::Wipe(TInt aLength) //dont call in drawing
{
TUint8* addr = LockSurface();
if(addr != NULL)
{
Mem::FillZ(addr, aLength);
UnlockHwSurface();
}
}
void CDsaB::UnlockHwSurface()
{
EpocSdlEnv::Request(CDsa::ERequestUpdate);
}
TUint8* CDsaB::LockSurface()
{
TUint8* addr = iSurface1->Address();
if(addr == NULL)
addr = iSurface2->Address();
SetUpdating(addr == NULL);
return addr;
}
void CDsaB::SurfaceReady()
{
SetUpdating(EFalse);
}
CDirectScreenBitmap& CDsaB::Dsb()
{
return *iDsb;
}
void CDsaB::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
if(iDsb == NULL)
iDsb = CDirectScreenBitmap::NewL();
CDsa::ConstructL(aWindow, aDevice);
iSurface1 = new (ELeave) CDsbSurface(*this);
iSurface2 = new (ELeave) CDsbSurface(*this);
}
CDsaB::~CDsaB()
{
delete iSurface1;
delete iSurface2;
delete iDsb;
}
void CDsaB::RecreateL()
{
iDsb->Close();
iDsb->Create(HwRect(), CDirectScreenBitmap::EDoubleBuffer);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
TSize CDsa::WindowSize() const
{
TSize size = HwRect().Size();
if(iStateFlags & EOrientation90)
{
const TInt tmp = size.iWidth;
size.iWidth = size.iHeight;
size.iHeight = tmp;
}
return size;
}
void CDsa::SetSuspend()
{
iStateFlags |= ESdlThreadSuspend;
}
void CDsa::ReleaseStop()
{
iStateFlags &= ~ESdlThreadExplicitStop;
}
TBool CDsa::Stopped() const
{
return (iStateFlags & ESdlThreadExplicitStop);
}
void CDsa::SetOrientation(CSDL::TOrientationMode aOrientation)
{
TInt flags = 0;
switch(aOrientation)
{
case CSDL::EOrientation90:
flags = EOrientation90;
break;
case CSDL::EOrientation180:
flags = EOrientation180;
break;
case CSDL::EOrientation270:
flags = EOrientation90 | EOrientation180;
break;
case CSDL::EOrientation0:
flags = 0;
break;
}
if(flags != (iStateFlags & EOrientationFlags))
{
iStateFlags |= EOrientationChanged;
iNewFlags = flags; //cannot be set during drawing...
}
}
CDsa::~CDsa()
{
if(iDsa != NULL)
{
iDsa->Cancel();
}
delete iDsa;
User::Free(iLut256);
}
void CDsa::ConstructL(RWindow& aWindow, CWsScreenDevice& aDevice)
{
if(iDsa != NULL)
{
iDsa->Cancel();
delete iDsa;
iDsa = NULL;
}
iDsa = CDirectScreenAccess::NewL(
iSession,
aDevice,
aWindow,
*this);
if(iLut256 == NULL)
iLut256 = (TUint32*) User::AllocL(256 * sizeof(TUint32));
iTargetMode = aWindow.DisplayMode();
iTargetBpp = BytesPerPixel(DisplayMode());
iTargetRect = TRect(aWindow.Position(), aWindow.Size());
RestartL();
}
void CDsa::LockPalette(TBool aLock)
{
if(aLock)
iStateFlags |= EPaletteLocked;
else
iStateFlags &= ~EPaletteLocked;
}
TInt CDsa::SetPalette(TInt aFirst, TInt aCount, TUint32* aPalette)
{
if(iLut256 == NULL)
return KErrNotFound;
const TInt count = aCount - aFirst;
if(count > 256)
return KErrArgument;
if(iStateFlags & EPaletteLocked)
return KErrNone;
for(TInt i = aFirst; i < count; i++) //not so busy here:-)
{
iLut256[i] = aPalette[i];
}
return KErrNone;
}
void CDsa::RestartL()
{
//const TBool active = iDsa->IsActive();
//if(!active)
iDsa->StartL();
RRegion* r = iDsa->DrawingRegion();
iDsa->Gc()->SetClippingRegion(r);
TRect rect = r->BoundingRect();
if(rect.IsEmpty())
{
return;
}
iScreenRect = rect; //to ensure properly set, albeit may not(?) match to value SDL has - therefore may has to clip
RecreateL();
iStateFlags |= ERunning;
// iScanLineWidth = iTargetBpp * HwRect().Width();
ReleaseStop();
if(iStateFlags & ESdlThreadSuspend)
{
EpocSdlEnv::Resume();
iStateFlags &= ~ ESdlThreadSuspend;
}
}
CDsa::CDsa(RWsSession& aSession) :
iSession(aSession),
iStateFlags(0)
{
// CActiveScheduler::Add(this);
iCFTable[0] = CopyMem;
iCFTable[1] = CopyMemFlipReversed;
iCFTable[2] = CopyMemReversed;
iCFTable[3] = CopyMemFlip;
iCFTable[4] = Copy256;
iCFTable[5] = Copy256FlipReversed;
iCFTable[6] = Copy256Reversed;
iCFTable[7] = Copy256Flip;
iCFTable[8] = CopySlow;
iCFTable[9] = CopySlowFlipReversed;
iCFTable[10] = CopySlowReversed;
iCFTable[11] = CopySlowFlip;
}
RWsSession& CDsa::Session()
{
return iSession;
}
TUint8* CDsa::LockHwSurface()
{
if((iStateFlags & EUpdating) == 0) //else frame is skipped
{
return LockSurface();
}
return NULL;
}
/*
void CDsa::RunL()
{
iStateFlags &= ~EUpdating;
}
void CDsa::DoCancel()
{
iStateFlags &= ~EUpdating;
//nothing can do, just wait?
}
*/
TInt CDsa::AllocSurface(TBool aHwSurface, const TSize& aSize, TDisplayMode aMode)
{
if(aHwSurface && aMode != DisplayMode())
return KErrArgument;
iSourceMode = aMode;
iSourceBpp = BytesPerPixel(aMode);
const TSize size = WindowSize();
if(aSize.iWidth > size.iWidth)
return KErrTooBig;
if(aSize.iHeight > size.iHeight)
return KErrTooBig;
TRAPD(err, CreateSurfaceL());
if(err != KErrNone)
return err;
SetCopyFunction();
EpocSdlEnv::ObserverEvent(MSDLObserver::EEventWindowReserved);
return KErrNone;
}
/*
void SaveBmp(const TDesC& aName, const TAny* aData, TInt aLength, const TSize& aSz, TDisplayMode aMode)
{
CFbsBitmap* s = new CFbsBitmap();
s->Create(aSz, aMode);
s->LockHeap();
TUint32* addr = s->DataAddress();
Mem::Copy(addr, aData, aLength);
s->UnlockHeap();
s->Save(aName);
s->Reset();
delete s;
}
void SaveBmp(const TDesC& aName, const TUint32* aData, const TSize& aSz)
{
CFbsBitmap* s = new CFbsBitmap();
s->Create(aSz, EColor64K);
TBitmapUtil bmp(s);
bmp.Begin(TPoint(0, 0));
for(TInt j = 0; j < aSz.iHeight; j++)
{
bmp.SetPos(TPoint(0, j));
for(TInt i = 0; i < aSz.iWidth; i++)
{
bmp.SetPixel(*aData);
aData++;
bmp.IncXPos();
}
}
bmp.End();
s->Save(aName);
s->Reset();
delete s;
}
TBuf<16> FooName(TInt aFoo)
{
TBuf<16> b;
b.Format(_L("C:\\pic%d.mbm"), aFoo);
return b;
}
*/
void CDsa::ClipCopy(TUint8* aTarget, const TUint8* aSource, const TRect& aRect, const TRect& aTargetPos) const
{
TUint8* target = aTarget;
const TUint8* source = aSource;
const TInt lineWidth = aRect.Width();
source += iSourceBpp * (aRect.iTl.iY * lineWidth);
TInt sourceStartOffset = iSourceBpp * aRect.iTl.iX;
source += sourceStartOffset;
target += iTargetBpp * ((aTargetPos.iTl.iY + aRect.iTl.iY ) * lineWidth);
TInt targetStartOffset = iTargetBpp * (aRect.iTl.iX + aTargetPos.iTl.iX);
target += targetStartOffset;
TUint32* targetPtr = reinterpret_cast<TUint32*>(target);
const TInt targetWidth = HwRect().Size().iWidth;
const TInt height = aRect.Height();
TInt lineMove = iStateFlags & EOrientation90 ? 1 : lineWidth;
if(iStateFlags & EOrientation180)
{
targetPtr += targetWidth * (height - 1);
for(TInt i = 0; i < height; i++) //source is always smaller
{
iCopyFunction(*this, targetPtr, source, lineWidth, height);
source += lineMove;
targetPtr -= targetWidth;
}
}
else
{
for(TInt i = 0; i < height; i++) //source is always smaller
{
iCopyFunction(*this, targetPtr, source, lineWidth, height);
source += lineMove;
targetPtr += targetWidth;
}
}
}
void CDsa::Wipe() //dont call in drawing
{
if(IsDsaAvailable())
Wipe(iTargetBpp * iScreenRect.Width() * iScreenRect.Height());
}
void CDsa::SetCopyFunction()
{
//calculate offset to correct function in iCFTable according to given parameters
TInt function = 0;
const TInt KCopyFunctions = 4;
const TInt KOffsetToNative = 0;
const TInt KOffsetTo256 = KOffsetToNative + KCopyFunctions;
const TInt KOffsetToOtherModes = KOffsetTo256 + KCopyFunctions;
const TInt KOffsetTo90Functions = 1;
const TInt KOffsetTo180Functions = 2;
if(iSourceMode == DisplayMode())
function = KOffsetToNative; //0
else if(iSourceMode == EColor256)
function = KOffsetTo256; //4
else
function = KOffsetToOtherModes; //8
if(iStateFlags & EOrientation90)
function += KOffsetTo90Functions; // + 1
if(iStateFlags & EOrientation180)
function += KOffsetTo180Functions; //+ 2
iCopyFunction = iCFTable[function];
Wipe();
}
inline void Rotate(TRect& aRect)
{
const TInt dx = aRect.iBr.iX - aRect.iTl.iX;
const TInt dy = aRect.iBr.iY - aRect.iTl.iY;
aRect.iBr.iX = aRect.iTl.iX + dy;
aRect.iBr.iY = aRect.iTl.iY + dx;
const TInt tmp = aRect.iTl.iX;
aRect.iTl.iX = aRect.iTl.iY;
aRect.iTl.iY = tmp;
}
/*
int bar = 0;
*/
TBool CDsa::AddUpdateRect(const TUint8* aBits, const TRect& aUpdateRect, const TRect& aRect)
{
if(iStateFlags & EOrientationChanged)
{
iStateFlags &= ~EOrientationFlags;
iStateFlags |= iNewFlags;
SetCopyFunction();
iStateFlags &= ~EOrientationChanged;
EpocSdlEnv::WaitDeviceChange();
return EFalse; //skip this frame as data is may be changed
}
if(iTargetAddr == NULL)
{
iTargetAddr = LockHwSurface();
}
TUint8* target = iTargetAddr;
if(target == NULL)
return EFalse;
TRect targetRect = HwRect();
TRect sourceRect = aRect;
TRect updateRect = aUpdateRect;
if(iStateFlags & EOrientation90)
{
Rotate(sourceRect);
Rotate(updateRect);
}
if(iSourceMode != DisplayMode() || targetRect != sourceRect || targetRect != updateRect || ((iStateFlags & EOrientationFlags) != 0))
{
sourceRect.Intersection(targetRect); //so source always smaller or equal than target
updateRect.Intersection(targetRect);
ClipCopy(target, aBits, updateRect, sourceRect);
}
else
{
const TInt byteCount = aRect.Width() * aRect.Height() * iSourceBpp; //this could be stored
Mem::Copy(target, aBits, byteCount);
}
return ETrue;
}
CDsa* CDsa::CreateL(RWsSession& aSession)
{
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSB))
{
TInt flags = CDirectScreenBitmap::ENone;
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSBDoubleBuffer))
flags |= CDirectScreenBitmap::EDoubleBuffer;
if(EpocSdlEnv::Flags(CSDL::EDrawModeDSBIncrentalUpdate))
flags |= CDirectScreenBitmap::EIncrementalUpdate;
return new (ELeave) CDsaB(aSession);
}
else
return new (ELeave) CDsaA(aSession);
}
void CDsa::CreateZoomerL(const TSize& aSize)
{
iSwSize = aSize;
iStateFlags |= EResizeRequest;
CreateSurfaceL();
SetTargetRect();
}
TPoint CDsa::WindowCoordinates(const TPoint& aPoint) const
{
TPoint pos = aPoint - iScreenRect.iTl;
const TSize asz = iScreenRect.Size();
if(iStateFlags & EOrientation180)
{
pos.iX = asz.iWidth - pos.iX;
pos.iY = asz.iHeight - pos.iY;
}
if(iStateFlags & EOrientation90)
{
pos.iX = aPoint.iY;
pos.iY = aPoint.iX;
}
pos.iX <<= 16;
pos.iY <<= 16;
pos.iX /= asz.iWidth;
pos.iY /= asz.iHeight;
pos.iX *= iSwSize.iWidth;
pos.iY *= iSwSize.iHeight;
pos.iX >>= 16;
pos.iY >>= 16;
return pos;
}
void CDsa::SetTargetRect()
{
iTargetRect = iScreenRect;
if(iStateFlags & EResizeRequest && EpocSdlEnv::Flags(CSDL::EAllowImageResizeKeepRatio))
{
const TSize asz = iScreenRect.Size();
const TSize sz = iSwSize;
TRect rect;
const TInt dh = (sz.iHeight << 16) / sz.iWidth;
if((asz.iWidth * dh ) >> 16 <= asz.iHeight)
{
rect.SetRect(TPoint(0, 0), TSize(asz.iWidth, (asz.iWidth * dh) >> 16));
}
else
{
const TInt dw = (sz.iWidth << 16) / sz.iHeight;
rect.SetRect(TPoint(0, 0), TSize((asz.iHeight * dw) >> 16, asz.iHeight));
}
rect.Move((asz.iWidth - rect.Size().iWidth) >> 1, (asz.iHeight - rect.Size().iHeight) >> 1);
iTargetRect = rect;
iTargetRect.Move(iScreenRect.iTl);
}
if(!(iStateFlags & EResizeRequest))
iSwSize = iScreenRect.Size();
// iScanLineWidth = /*iTargetBpp **/ SwSize().iWidth;
}
void CDsa::RecreateL()
{
}
void CDsa::Free()
{
}
void CDsa::UpdateSwSurface()
{
iTargetAddr = NULL;
UnlockHwSurface(); //could be faster if does not use AO, but only check status before redraw, then no context switch needed
}
void CDsa::SetBlitter(MBlitter* aBlitter)
{
iBlitter = aBlitter;
}
void CDsa::DrawOverlays()
{
const TInt last = iOverlays.Count() - 1;
for(TInt i = last; i >= 0 ; i--)
iOverlays[i].iOverlay->Draw(*iDsa->Gc(), HwRect(), SwSize());
}
TInt CDsa::AppendOverlay(MOverlay& aOverlay, TInt aPriority)
{
TInt i;
for(i = 0; i < iOverlays.Count() && iOverlays[i].iPriority < aPriority; i++)
{}
const TOverlay overlay = {&aOverlay, aPriority};
return iOverlays.Insert(overlay, i);
}
TInt CDsa::RemoveOverlay(MOverlay& aOverlay)
{
for(TInt i = 0; i < iOverlays.Count(); i++)
{
if(iOverlays[i].iOverlay == &aOverlay)
{
iOverlays.Remove(i);
return KErrNone;
}
}
return KErrNotFound;
}
TInt CDsa::RedrawRequest()
{
if(!(iStateFlags & (EUpdating) && (iStateFlags & ERunning)))
{
return ExternalUpdate();
}
return KErrNotReady;
}
void CDsa::Resume()
{
if(Stopped())
Restart(RDirectScreenAccess::ETerminateRegion);
}
void CDsa::DoStop()
{
if(IsDsaAvailable())
iStateFlags |= ESdlThreadExplicitStop;
Stop();
}
void CDsa::Stop()
{
iStateFlags &= ~ERunning;
// Cancel(); //can be called only from main!
iDsa->Cancel();
}
void CDsa::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/)
{
// iStateFlags |= EChangeNotify;
Stop();
}
void CDsa::Restart(RDirectScreenAccess::TTerminationReasons aReason)
{
if(aReason == RDirectScreenAccess::ETerminateRegion) //auto restart
{
TRAPD(err, RestartL());
PANIC_IF_ERROR(err);
}
}
/*)
TBool CDsa::ChangeTrigger()
{
const TBool change = iStateFlags & EChangeNotify;
iStateFlags &= ~EChangeNotify;
return change;
}
*/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CDsa::Copy256(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint8* source = aSource;
while(target < endt)
{
*target++ = aDsa.iLut256[*source++];
}
}
void CDsa::Copy256Reversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint8* source = aSource;
while(target < endt)
{
*(--endt) = aDsa.iLut256[*source++];
}
}
void CDsa::Copy256Flip(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint8* column = aSource;
while(target < endt)
{
*target++ = aDsa.iLut256[*column];
column += aLineLen;
}
}
void CDsa::Copy256FlipReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint8* column = aSource;
while(target < endt)
{
*(--endt) = aDsa.iLut256[*column];
column += aLineLen;
}
}
void CDsa::CopyMem(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
Mem::Copy(aTarget, aSource, aBytes);
}
void CDsa::CopyMemFlip(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TUint32* target = aTarget;
const TUint32* endt = target + aBytes;
const TUint32* column = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*target++ = *column;
column += aLineLen;
}
}
void CDsa::CopyMemReversed(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint32* source = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*(--endt) = *source++;
}
}
void CDsa::CopyMemFlipReversed(const CDsa& /*aDsa*/, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
const TUint32* target = aTarget;
TUint32* endt = aTarget + aBytes;
const TUint32* column = reinterpret_cast<const TUint32*>(aSource);
while(target < endt)
{
*(--endt) = *column;
column += aLineLen;
}
}
typedef TRgb (*TRgbFunc) (TInt aValue);
LOCAL_C TRgb rgb16MA(TInt aValue)
{
return TRgb::Color16MA(aValue);
}
NONSHARABLE_CLASS(MRgbCopy)
{
public:
virtual void Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed) = 0;
virtual void FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed) = 0;
};
template <class T>
NONSHARABLE_CLASS(TRgbCopy) : public MRgbCopy
{
public:
TRgbCopy(TDisplayMode aMode);
void* operator new(TUint aBytes, TAny* aMem);
void Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed);
void FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed);
private:
TRgbFunc iFunc;
};
template <class T>
void* TRgbCopy<T>::operator new(TUint /*aBytes*/, TAny* aMem)
{
return aMem;
}
template <class T>
TRgbCopy<T>::TRgbCopy(TDisplayMode aMode)
{
switch(aMode)
{
case EGray256 : iFunc = TRgb::Gray256; break;
case EColor256 : iFunc = TRgb::Color256; break;
case EColor4K : iFunc = TRgb::Color4K; break;
case EColor64K : iFunc = TRgb::Color64K; break;
case EColor16M : iFunc = TRgb::Color16M; break;
case EColor16MU : iFunc = TRgb::Color16MU; break;
case EColor16MA : iFunc = rgb16MA; break;
default:
PANIC(KErrNotSupported);
}
}
template <class T>
void TRgbCopy<T>::Copy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TBool aReversed)
{
const T* source = reinterpret_cast<const T*>(aSource);
TUint32* target = aTarget;
TUint32* endt = target + aBytes;
if(aReversed)
{
while(target < endt)
{
TUint32 value = *source++;
*(--endt) = iFunc(value).Value();
}
}
else
{
while(target < endt)
{
TUint32 value = *source++;
*target++ = iFunc(value).Value();
}
}
}
template <class T>
void TRgbCopy<T>::FlipCopy(TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen, TBool aReversed)
{
const T* column = reinterpret_cast<const T*>(aSource);
TUint32* target = aTarget;
TUint32* endt = target + aBytes;
if(aReversed)
{
while(target < endt)
{
*(--endt) = iFunc(*column).Value();
column += aLineLen;
}
}
else
{
while(target < endt)
{
*target++ = iFunc(*column).Value();
column += aLineLen;
}
}
}
typedef TUint64 TStackMem;
LOCAL_C MRgbCopy* GetCopy(TAny* mem, TDisplayMode aMode)
{
if(aMode == EColor256 || aMode == EGray256)
{
return new (mem) TRgbCopy<TUint8>(aMode);
}
if(aMode == EColor4K || aMode == EColor64K)
{
return new (mem) TRgbCopy<TUint16>(aMode);
}
if(aMode == EColor16M || aMode == EColor16MU || aMode == EColor16MA)
{
return new (mem) TRgbCopy<TUint32>(aMode);
}
PANIC(KErrNotSupported);
return NULL;
}
void CDsa::CopySlowFlipReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->FlipCopy(aTarget, aSource, aBytes, aLineLen, ETrue);
}
void CDsa::CopySlowFlip(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt aLineLen)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->FlipCopy(aTarget, aSource, aBytes, aLineLen, EFalse);
}
void CDsa::CopySlow(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->Copy(aTarget, aSource, aBytes, EFalse);
}
void CDsa::CopySlowReversed(const CDsa& aDsa, TUint32* aTarget, const TUint8* aSource, TInt aBytes, TInt)
{
TStackMem mem = 0;
GetCopy(&mem, aDsa.iSourceMode)->Copy(aTarget, aSource, aBytes, ETrue);
}
\ No newline at end of file
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@devolution.com
*/
/*
SDL_epocevents_c.h
Handle the event stream, converting Epoc events into SDL events
Epoc version by Hannu Viitala (hannu.j.viitala@mbnet.fi) and Markus Mertama
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_aaevents_c.h,v 1.1.2.2 2000/03/16 15:20:39 hercules Exp $";
#endif
extern "C" {
#include "SDL_sysvideo.h"
//#include "SDL_epocvideo.h"
}
#define MAX_SCANCODE 255
/* Variables and functions exported by SDL_sysevents.c to other parts
of the native video subsystem (SDL_sysvideo.c)
*/
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_VideoDevice *_this
#define Private _this->hidden
extern "C" {
extern void EPOC_InitOSKeymap(_THIS);
extern void EPOC_PumpEvents(_THIS);
}
extern TBool isCursorVisible;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment