Remove observer support.
[SDL.s60v3.git] / src / main / symbian / SDL_main.cpp
blobdfedeb8ba62dec2993decae3e7c6cd8769cb50a1
1 extern "C" {
2 #include "SDL_events_c.h"
4 #include <queue>
5 #include "epoc_sdl.h"
6 #include "sdlepocapi.h"
7 #include <e32base.h>
8 #include <estlib.h>
9 #include <stdio.h>
10 #include <badesca.h>
11 #include <w32std.h>
12 #include <aknappui.h>
13 #include <aknapp.h>
14 #include "SDL_epocevents_c.h"
15 #include "SDL_keysym.h"
16 #include "dsa.h"
17 #include "SDL_loadso.h"
18 #include <remconcoreapitargetobserver.h>
19 #include <remconinterfaceselector.h>
20 #include <remconcoreapitarget.h>
22 extern SDLKey* KeyMap();
23 extern void ResetKeyMap();
25 class CCurrentAppUi;
26 class CEikonEnv;
27 class CSdlAppServ;
28 class CEventQueue;
30 class EpocSdlEnvData
32 public:
33 void Free();
34 void Delete();
35 CEventQueue* iEventQueue;
36 TMainFunc iMain;
37 int iEpocEnvFlags;
38 int iArgc;
39 char** iArgv;
40 CDsa* iDsa;
41 CSdlAppServ* iAppSrv;
42 TThreadId iId;
43 CArrayFix<TSdlCleanupItem>* iCleanupItems;
44 CSDL* iSdl;
45 TRequestStatus* iCallerStatus;
46 bool iWaitingForOrientationChange;
48 TSize iSize;
49 TDisplayMode iMode;
52 EpocSdlEnvData* gEpocEnv;
54 class EnvUtils
56 public:
57 static void RunSingleThread();
60 void EnvUtils::RunSingleThread()
62 int count = RThread().RequestCount();
63 if(count > 0)
65 int err;
66 if(CActiveScheduler::RunIfReady(err, CActive::EPriorityIdle))
68 CActiveScheduler::Current()->WaitForAnyRequest();
73 int Panic(int aErr, int aLine)
75 TBuf<64> b;
76 b.Format(_L("Main at %d"), aLine);
77 User::Panic(b, aErr);
78 return 0;
82 class CEventQueue : public CBase, public MEventQueue
84 public:
85 void ConstructL();
86 ~CEventQueue();
87 int Append(const TWsEvent& aEvent);
88 const TWsEvent Shift();
89 TBool HasData();
91 private:
92 std::queue<TWsEvent> m_queue;
95 void CEventQueue::ConstructL()
99 CEventQueue::~CEventQueue()
103 int CEventQueue::Append(const TWsEvent& aEvent)
105 m_queue.push(aEvent);
106 return 0;
109 TBool CEventQueue::HasData()
111 EnvUtils::RunSingleThread();
112 return !m_queue.empty();
115 const TWsEvent CEventQueue::Shift()
117 const TWsEvent event = m_queue.front();
118 m_queue.pop();
119 return event;
123 TSdlCleanupItem::TSdlCleanupItem(TSdlCleanupOperation aOperation, TAny* aItem) :
124 iOperation(aOperation), iItem(aItem), iThread(RThread().Id())
127 #define MAINFUNC(x) TMainFunc::TMainFunc(mainfunc##x aFunc){Mem::FillZ(iMainFunc, sizeof(iMainFunc)); iMainFunc[x - 1] = (void*) aFunc;}
129 MAINFUNC(1)
130 MAINFUNC(2)
131 MAINFUNC(3)
132 MAINFUNC(4)
133 MAINFUNC(5)
134 MAINFUNC(6)
136 TMainFunc::TMainFunc()
138 Mem::FillZ(iMainFunc, sizeof(iMainFunc));
142 const void* TMainFunc::operator[](int aIndex) const
144 return iMainFunc[aIndex];
148 class CSdlAppServ : public CActive
150 public:
151 enum
153 EAppSrvNoop = CDsa::ELastDsaRequest,
154 EAppSrvWindowWidth,
155 EAppSrvWindowHeight,
156 EAppSrvWindowDisplayMode,
157 EAppSrvWindowPointerCursorMode,
158 EAppSrvDsaStatus,
159 EAppSrvStopThread,
160 EAppSrvWaitDsa
162 CSdlAppServ();
163 void ConstructL();
164 ~CSdlAppServ();
165 int Request(int aService);
166 int RequestValue(int aService);
167 void Init();
168 void PanicMain(int aReason);
169 void PanicMain(const TDesC& aInfo, int aReason);
170 void SetParam(int aParam);
172 private:
173 void RunL();
174 void DoCancel();
175 const TThreadId iMainId;
176 RThread iAppThread;
177 int iService;
178 int iReturnValue;
179 TRequestStatus* iStatusPtr;
182 CSdlAppServ::CSdlAppServ() : CActive(CActive::EPriorityHigh), iMainId(RThread().Id())
185 void CSdlAppServ::PanicMain(int aReason)
187 iAppThread.Panic(RThread().Name(), aReason);
190 void CSdlAppServ::PanicMain(const TDesC& aInfo, int aReason)
192 iAppThread.Panic(aInfo, aReason);
195 void CSdlAppServ::ConstructL()
197 CActiveScheduler::Add(this);
198 iStatus = KRequestPending;
199 iStatusPtr = &iStatus;
200 SetActive();
203 CSdlAppServ::~CSdlAppServ()
205 Cancel();
206 iAppThread.Close();
209 int CSdlAppServ::Request(int aService)
211 EnvUtils::RunSingleThread();
212 iService = aService;
213 iAppThread.RequestComplete(iStatusPtr, KErrNone);
214 return KErrNone;
217 int CSdlAppServ::RequestValue(int aService)
219 Request(aService);
220 Request(EAppSrvNoop);
221 return iReturnValue;
224 void CSdlAppServ::Init()
226 PANIC_IF_ERROR(iAppThread.Open(iMainId));
229 void CSdlAppServ::SetParam(int aParam)
231 iReturnValue = aParam;
234 void CSdlAppServ::RunL()
236 if(iStatus == KErrNone)
238 switch(iService)
240 case CSdlAppServ::EAppSrvWaitDsa:
241 EpocSdlEnv::SetWaitDsa();
242 iReturnValue = EpocSdlEnv::IsDsaAvailable();
243 break;
245 case CSdlAppServ::EAppSrvStopThread:
246 if(gEpocEnv->iDsa != NULL)
247 gEpocEnv->iDsa->SetSuspend();
248 break;
250 case EAppSrvWindowPointerCursorMode:
251 iReturnValue = gEpocEnv->iDsa != NULL ? gEpocEnv->iDsa->Session().PointerCursorMode() : KErrNotReady;
252 break;
254 case EAppSrvDsaStatus:
255 if(gEpocEnv->iDsa != NULL)
256 gEpocEnv->iDsa->Stop();
257 iReturnValue = KErrNone;
258 break;
260 case EAppSrvNoop:
261 break;
263 default:
264 PANIC(KErrNotSupported);
265 break;
268 iStatus = KRequestPending;
269 iStatusPtr = &iStatus;
270 SetActive();
274 void CSdlAppServ::DoCancel()
276 TRequestStatus* s = &iStatus;
277 iAppThread.RequestComplete(s, KErrCancel);
280 MEventQueue& EpocSdlEnv::EventQueue()
282 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
283 return *gEpocEnv->iEventQueue;
287 TBool EpocSdlEnv::Flags(int aFlag)
289 const int flag = gEpocEnv->iEpocEnvFlags & aFlag;
290 return flag == aFlag;
293 int EpocSdlEnv::Argc()
295 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
296 return gEpocEnv->iArgc;
299 char** EpocSdlEnv::Argv()
301 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
302 return gEpocEnv->iArgv;
305 TBool EpocSdlEnv::IsDsaAvailable()
307 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
308 return gEpocEnv->iDsa != NULL && gEpocEnv->iDsa->IsDsaAvailable();
311 void EpocSdlEnv::WaitDsaAvailable()
313 gEpocEnv->iAppSrv->Request(CSdlAppServ::EAppSrvStopThread);
316 void EpocSdlEnv::Suspend()
318 if(gEpocEnv->iDsa != NULL && (gEpocEnv->iDsa->Stopped() || EpocSdlEnv::Flags(CSDL::EEnableFocusStop)))
320 gEpocEnv->iDsa->SetSuspend();
324 void EpocSdlEnv::SetWaitDsa()
326 if(!IsDsaAvailable())
328 if(gEpocEnv->iDsa != NULL)
329 gEpocEnv->iDsa->SetSuspend();
333 void EpocSdlEnv::Resume()
335 if(gEpocEnv->iDsa != NULL)
337 gEpocEnv->iDsa->Resume();
341 int EpocSdlEnv::AllocSurface(const TSize& aSize, TDisplayMode aMode)
343 return gEpocEnv->iDsa->AllocSurface(aSize, aMode);
346 void EpocSdlEnv::UnlockHwSurface()
348 gEpocEnv->iDsa->UnlockHwSurface();
351 TUint8* EpocSdlEnv::LockHwSurface()
353 return gEpocEnv->iDsa->LockHwSurface();
356 void EpocSdlEnv::UpdateSwSurface()
358 gEpocEnv->iDsa->UpdateSwSurface();
361 TBool EpocSdlEnv::AddUpdateRect(TUint8* aAddress, const TRect& aUpdateRect, const TRect& aRect)
363 return gEpocEnv->iDsa->AddUpdateRect(aAddress, aUpdateRect, aRect);
366 void EpocSdlEnv::Request(int aService)
368 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
369 gEpocEnv->iAppSrv->Request(aService);
372 TDisplayMode EpocSdlEnv::DisplayMode()
374 return gEpocEnv->iDsa == NULL ? ENone : gEpocEnv->iDsa->DisplayMode();
377 TPointerCursorMode EpocSdlEnv::PointerMode()
379 return static_cast<TPointerCursorMode>(gEpocEnv->iAppSrv->RequestValue(CSdlAppServ::EAppSrvWindowPointerCursorMode));
382 int EpocSdlEnv::SetPalette(int aFirstcolor, int aColorCount, TUint32* aPalette)
384 return gEpocEnv->iDsa->SetPalette(aFirstcolor, aColorCount, aPalette);
387 void EpocSdlEnv::PanicMain(int aErr)
389 gEpocEnv->iAppSrv->PanicMain(aErr);
393 int EpocSdlEnv::AppendCleanupItem(const TSdlCleanupItem& aItem)
395 TRAPD(err, gEpocEnv->iCleanupItems->AppendL(aItem));
396 return err;
399 void EpocSdlEnv::RemoveCleanupItem(TAny* aItem)
401 for(int i = 0; i < gEpocEnv->iCleanupItems->Count(); i++)
403 if(gEpocEnv->iCleanupItems->At(i).iItem == aItem)
404 gEpocEnv->iCleanupItems->Delete(i);
408 void EpocSdlEnv::CleanupItems()
410 const TThreadId id = RThread().Id();
411 int last = gEpocEnv->iCleanupItems->Count() - 1;
412 int i;
414 for(i = last; i >= 0 ; i--)
416 TSdlCleanupItem& item = gEpocEnv->iCleanupItems->At(i);
417 if(item.iThread == id)
419 item.iThread = TThreadId(0);
420 item.iOperation(item.iItem);
424 last = gEpocEnv->iCleanupItems->Count() - 1;
426 for(i = last; i >= 0 ; i--)
428 TSdlCleanupItem& item = gEpocEnv->iCleanupItems->At(i);
429 if(item.iThread == TThreadId(0))
431 gEpocEnv->iCleanupItems->Delete(i);
436 void EpocSdlEnv::FreeSurface()
438 Request(CSdlAppServ::EAppSrvDsaStatus);
439 if(gEpocEnv->iDsa != NULL)
440 gEpocEnv->iDsa->Free();
443 void EpocSdlEnv::PanicMain(const TDesC& aInfo, int aErr)
445 gEpocEnv->iAppSrv->PanicMain(aInfo, aErr);
448 //Dsa is a low priority ao, it has to wait if its pending event, but ws
449 //event has been prioritized before it
450 //this is not called from app thread!
451 void EpocSdlEnv::WaitDeviceChange()
453 gEpocEnv->iAppSrv->RequestValue(CSdlAppServ::EAppSrvWaitDsa);
456 static TBool CheckSdl()
458 int isExit = ETrue;
459 RThread sdl;
460 if(sdl.Open(gEpocEnv->iId) == KErrNone)
462 if(sdl.ExitType() == EExitPending)
464 isExit = EFalse;
466 sdl.Close();
468 return isExit;
471 void EpocSdlEnvData::Free()
473 if(RThread().Id() == gEpocEnv->iId)
475 if(iDsa != NULL)
476 iDsa->Free();
477 return;
480 __ASSERT_ALWAYS(iArgv == NULL || CheckSdl(), PANIC(KErrNotReady));
483 void EpocSdlEnvData::Delete()
485 for(int i = 0; i <= iArgc; i++)
487 if(iArgv != NULL)
488 delete[] iArgv[i];
491 delete[] iArgv;
493 iArgv = NULL;
494 iArgc = 0;
496 delete iEventQueue;
498 if(iDsa != NULL)
499 iDsa->Free();
501 delete iDsa;
502 delete iAppSrv;
505 _LIT(KSDLMain, "SDLMain");
507 static int MainL()
509 gEpocEnv->iCleanupItems = new CArrayFixFlat<TSdlCleanupItem>(8);
511 char** envp=0;
512 /* !! process exits here if there is "exit()" in main! */
513 int ret = 0;
514 for(int i = 0; i < 6; i++)
516 void* f = (void*) gEpocEnv->iMain[i];
517 if(f != NULL)
519 switch(i)
521 case 0:
522 ret = ((mainfunc1)f)();
523 return ret;
525 case 3:
526 ((mainfunc1)f)();
527 return ret;
529 case 1:
530 ret = ((mainfunc2)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv());
531 return ret;
533 case 4:
534 ((mainfunc2)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv());
535 return ret;
537 case 2:
538 ret = ((mainfunc3)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv(), envp);
539 return ret;
541 case 5:
542 ((mainfunc3)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv(), envp);
543 return ret;
547 PANIC(KErrNotFound);
548 return 0;
551 static int DoMain(TAny* /*aParam*/)
553 TBool fbsconnected = EFalse;
555 gEpocEnv->iAppSrv->Init();
557 // Call stdlib main
558 int ret = 0;
560 TRAPD(err, err = MainL());
562 // Free resources and return
563 EpocSdlEnv::CleanupItems();
565 gEpocEnv->iCleanupItems->Reset();
566 delete gEpocEnv->iCleanupItems;
567 gEpocEnv->iCleanupItems = NULL;
569 gEpocEnv->Free(); //free up in thread resources
571 if(fbsconnected)
572 RFbsSession::Disconnect();
574 if(gEpocEnv->iCallerStatus != NULL)
576 User::RequestComplete(gEpocEnv->iCallerStatus, err);
577 return 0;
579 else
581 return err == KErrNone ? ret : err;
585 CSDL::~CSDL()
587 gEpocEnv->Free();
588 gEpocEnv->Delete();
590 delete gEpocEnv;
591 gEpocEnv = NULL;
594 CSDL* CSDL::NewL(int aFlags)
596 __ASSERT_ALWAYS(gEpocEnv == NULL, PANIC(KErrAlreadyExists));
597 gEpocEnv = new EpocSdlEnvData;
598 Mem::FillZ(gEpocEnv, sizeof(EpocSdlEnvData));
600 gEpocEnv->iEpocEnvFlags = aFlags;
601 gEpocEnv->iEventQueue = new CEventQueue();
602 gEpocEnv->iAppSrv = new CSdlAppServ();
604 CSDL* sdl = new CSDL();
606 gEpocEnv->iSdl = sdl;
608 return sdl;
611 void CSDL::SetContainerWindowL(RWindow& aWindow, RWsSession& aSession, CWsScreenDevice& aDevice)
613 if(gEpocEnv->iDsa == NULL)
614 gEpocEnv->iDsa = CDsa::CreateL(aSession);
615 gEpocEnv->iDsa->ConstructL(aWindow, aDevice);
618 int EpocSdlEnv::ApplyGlesDsa()
620 CDsa* dsa = NULL;
621 TRAPD(err, dsa = gEpocEnv->iDsa->CreateGlesDsaL());
622 gEpocEnv->iDsa = dsa;
623 return err;
626 RWindow* EpocSdlEnv::Window()
628 return gEpocEnv->iDsa->Window();
631 void EpocSdlEnv::UpdateWholeScreen(bool val)
633 gEpocEnv->iDsa->m_updateWholeScreen = val;
636 bool EpocSdlEnv::GetUpdateWholeScreen()
638 return gEpocEnv->iDsa->m_updateWholeScreen;
641 void EpocSdlEnv::SetOrientation(CAknAppUi::TAppUiOrientation orientation, const TSize& aSize, TDisplayMode aMode)
643 gEpocEnv->iWaitingForOrientationChange = true;
644 gEpocEnv->iSize = aSize;
645 gEpocEnv->iMode = aMode;
647 TRAPD(err, static_cast<CAknAppUi*>(CEikonEnv::Static()->EikAppUi())->SetOrientationL(orientation));
650 TThreadId CSDL::CallMainL(const TMainFunc& aFunc, TRequestStatus* const aStatus, const CDesC8Array* const aArg, int aStackSize)
652 ASSERT(gEpocEnv != NULL);
653 gEpocEnv->iMain = aFunc;
654 const TBool args = aArg != NULL;
656 if(gEpocEnv->iArgv != NULL)
657 User::Leave(KErrAlreadyExists);
659 gEpocEnv->iArgc = args ? aArg->Count() + 1 : 0;
660 gEpocEnv->iArgv = new char*[gEpocEnv->iArgc + 2];
662 int k = 0;
663 const TFileName processName = RProcess().FileName();
664 const int len = processName.Length();
665 gEpocEnv->iArgv[k] = new char[len + 1];
666 Mem::Copy(gEpocEnv->iArgv[k], processName.Ptr(), len);
667 gEpocEnv->iArgv[k][len] = 0;
669 for(int i = 0; args && (i < aArg->Count()); i++)
671 k++;
672 const int len = aArg->MdcaPoint(i).Length();
673 gEpocEnv->iArgv[k] = new char[len + 1];
674 Mem::Copy(gEpocEnv->iArgv[k], aArg->MdcaPoint(i).Ptr(), len);
675 gEpocEnv->iArgv[k][len] = 0;
678 gEpocEnv->iArgv[k + 1] = NULL;
680 gEpocEnv->iEventQueue->ConstructL();
681 gEpocEnv->iAppSrv->ConstructL();
683 // for handling volume up/down keys
684 CRemConInterfaceSelector *iSelector = CRemConInterfaceSelector::NewL();
685 CRemConCoreApiTarget::NewL( *iSelector, *this );
686 iSelector->OpenTargetL();
688 gEpocEnv->iCallerStatus = aStatus;
689 if(aStatus != NULL)
690 *aStatus = KRequestPending;
691 gEpocEnv->iId = RThread().Id();
692 // when priority is not lowered screen updates much more frequently, which
693 // may be undesired, for example in case of openttd's generating world dialog
694 RThread().SetPriority(EPriorityLess);
695 DoMain( NULL );
697 return gEpocEnv->iId;
700 int CSDL::AppendWsEvent(const TWsEvent& aEvent)
702 return EpocSdlEnv::EventQueue().Append(aEvent);
705 void CSDL::SDLPanic(const TDesC& aInfo, int aErr)
707 EpocSdlEnv::PanicMain(aInfo, aErr);
710 int CSDL::GetSDLCode(int aScanCode)
712 if(aScanCode < 0)
713 return MAX_SCANCODE;
714 if(aScanCode >= MAX_SCANCODE)
715 return -1;
716 return KeyMap()[aScanCode];
719 int CSDL::SDLCodesCount() const
721 return MAX_SCANCODE;
724 void CSDL::ResetSDLCodes()
726 ResetKeyMap();
729 int CSDL::SetSDLCode(int aScanCode, int aSDLCode)
731 const int current = GetSDLCode(aScanCode);
732 if(aScanCode >= 0 && aScanCode < MAX_SCANCODE)
733 KeyMap()[aScanCode] = static_cast<SDLKey>(aSDLCode);
734 return current;
737 void CSDL::Resume()
739 EpocSdlEnv::Resume();
742 void CSDL::Suspend()
744 if(gEpocEnv->iDsa != NULL)
745 gEpocEnv->iDsa->DoStop();
748 void CSDL::Resize()
750 if(gEpocEnv->iWaitingForOrientationChange)
752 EpocSdlEnv::AllocSurface(gEpocEnv->iSize, gEpocEnv->iMode);
753 gEpocEnv->iWaitingForOrientationChange = false;
755 else
757 TSize size = gEpocEnv->iDsa->Window()->Size();
758 SDL_PrivateResize(size.iWidth, size.iHeight);
762 CSDL::CSDL()
765 void CSDL::MrccatoCommand(TRemConCoreApiOperationId aOperationId, TRemConCoreApiButtonAction aButtonAct)
767 if(aButtonAct != ERemConCoreApiButtonClick)
768 return;
770 TWsEvent event;
771 event.SetType(EEventKey);
772 event.SetTimeNow();
774 switch(aOperationId)
776 case ERemConCoreApiVolumeDown:
777 event.Key()->iScanCode = EStdKeyDecVolume;
778 event.SetType(EEventKeyDown);
779 AppendWsEvent(event);
780 event.SetType(EEventKeyUp);
781 AppendWsEvent(event);
782 break;
784 case ERemConCoreApiVolumeUp:
785 event.Key()->iScanCode = EStdKeyIncVolume;
786 event.SetType(EEventKeyDown);
787 AppendWsEvent(event);
788 event.SetType(EEventKeyUp);
789 AppendWsEvent(event);
790 break;
792 default:
793 break;
797 void* SDL_LoadObject(const char *sofile)
799 RLibrary* lib = new RLibrary();
800 if(lib == NULL)
801 return NULL;
802 TFileName name;
803 name.Copy(TPtrC8((const TUint8*)sofile));
804 if(KErrNone == lib->Load(name))
805 return lib;
806 delete lib;
807 return NULL;
810 void* SDL_LoadFunction(void *handle, const char *name)
812 TLex8 v((const TUint8*)(name));
813 int ord;
815 if(KErrNone != v.Val(ord))
816 return NULL;
818 const RLibrary* lib = reinterpret_cast<RLibrary*>(handle);
819 TLibraryFunction f = lib->Lookup(ord);
820 return (void*)(f);
823 void SDL_UnloadObject(void *handle)
825 RLibrary* lib = reinterpret_cast<RLibrary*>(handle);
826 lib->Close();
827 delete lib;