Remove stack size from CSDL::CallMainL().
[SDL.s60v3.git] / src / main / symbian / SDL_main.cpp
blob02314c212743570c30bbe17561f26ff4022f5936
1 extern "C" {
2 #include "SDL_events_c.h"
4 #include "epoc_sdl.h"
5 #include "sdlepocapi.h"
6 #include <e32base.h>
7 #include <estlib.h>
8 #include <stdio.h>
9 #include <badesca.h>
10 #include <w32std.h>
11 #include <aknappui.h>
12 #include <aknapp.h>
13 #include "SDL_epocevents_c.h"
14 #include "SDL_keysym.h"
15 #include "dsa.h"
16 #include "SDL_loadso.h"
17 #include <remconcoreapitargetobserver.h>
18 #include <remconinterfaceselector.h>
19 #include <remconcoreapitarget.h>
21 extern SDLKey* KeyMap();
22 extern void ResetKeyMap();
24 class CCurrentAppUi;
25 class CEikonEnv;
26 class CSdlAppServ;
27 class CEventQueue;
29 class EpocSdlEnvData
31 public:
32 void Free();
33 void Delete();
34 CEventQueue* iEventQueue;
35 TMainFunc iMain;
36 int iArgc;
37 char** iArgv;
38 CDsa* iDsa;
39 CSdlAppServ* iAppSrv;
40 TThreadId iId;
41 CArrayFix<TSdlCleanupItem>* iCleanupItems;
42 CSDL* iSdl;
43 TRequestStatus* iCallerStatus;
44 bool iWaitingForOrientationChange;
46 TSize iSize;
47 TDisplayMode iMode;
50 EpocSdlEnvData* gEpocEnv;
52 class EnvUtils
54 public:
55 static void RunSingleThread();
58 void EnvUtils::RunSingleThread()
60 int count = RThread().RequestCount();
61 if(count > 0)
63 int err;
64 if(CActiveScheduler::RunIfReady(err, CActive::EPriorityIdle))
66 CActiveScheduler::Current()->WaitForAnyRequest();
71 int Panic(int aErr, int aLine)
73 TBuf<64> b;
74 b.Format(_L("Main at %d"), aLine);
75 User::Panic(b, aErr);
76 return 0;
80 bool CEventQueue::HasData()
82 EnvUtils::RunSingleThread();
83 return !m_queue.empty();
86 const TWsEvent CEventQueue::Shift()
88 const TWsEvent event = m_queue.front();
89 m_queue.pop();
90 return event;
94 TSdlCleanupItem::TSdlCleanupItem(TSdlCleanupOperation aOperation, TAny* aItem) :
95 iOperation(aOperation), iItem(aItem), iThread(RThread().Id())
98 #define MAINFUNC(x) TMainFunc::TMainFunc(mainfunc##x aFunc){Mem::FillZ(iMainFunc, sizeof(iMainFunc)); iMainFunc[x - 1] = (void*) aFunc;}
100 MAINFUNC(1)
101 MAINFUNC(2)
102 MAINFUNC(3)
103 MAINFUNC(4)
104 MAINFUNC(5)
105 MAINFUNC(6)
107 TMainFunc::TMainFunc()
109 Mem::FillZ(iMainFunc, sizeof(iMainFunc));
113 const void* TMainFunc::operator[](int aIndex) const
115 return iMainFunc[aIndex];
119 class CSdlAppServ : public CActive
121 public:
122 enum
124 EAppSrvNoop = CDsa::ELastDsaRequest,
125 EAppSrvWindowWidth,
126 EAppSrvWindowHeight,
127 EAppSrvWindowDisplayMode,
128 EAppSrvWindowPointerCursorMode,
129 EAppSrvDsaStatus,
130 EAppSrvStopThread,
131 EAppSrvWaitDsa
133 CSdlAppServ();
134 void ConstructL();
135 ~CSdlAppServ();
136 int Request(int aService);
137 int RequestValue(int aService);
138 void Init();
139 void PanicMain(int aReason);
140 void PanicMain(const TDesC& aInfo, int aReason);
141 void SetParam(int aParam);
143 private:
144 void RunL();
145 void DoCancel();
146 const TThreadId iMainId;
147 RThread iAppThread;
148 int iService;
149 int iReturnValue;
150 TRequestStatus* iStatusPtr;
153 CSdlAppServ::CSdlAppServ() : CActive(CActive::EPriorityHigh), iMainId(RThread().Id())
156 void CSdlAppServ::PanicMain(int aReason)
158 iAppThread.Panic(RThread().Name(), aReason);
161 void CSdlAppServ::PanicMain(const TDesC& aInfo, int aReason)
163 iAppThread.Panic(aInfo, aReason);
166 void CSdlAppServ::ConstructL()
168 CActiveScheduler::Add(this);
169 iStatus = KRequestPending;
170 iStatusPtr = &iStatus;
171 SetActive();
174 CSdlAppServ::~CSdlAppServ()
176 Cancel();
177 iAppThread.Close();
180 int CSdlAppServ::Request(int aService)
182 EnvUtils::RunSingleThread();
183 iService = aService;
184 iAppThread.RequestComplete(iStatusPtr, KErrNone);
185 return KErrNone;
188 int CSdlAppServ::RequestValue(int aService)
190 Request(aService);
191 Request(EAppSrvNoop);
192 return iReturnValue;
195 void CSdlAppServ::Init()
197 PANIC_IF_ERROR(iAppThread.Open(iMainId));
200 void CSdlAppServ::SetParam(int aParam)
202 iReturnValue = aParam;
205 void CSdlAppServ::RunL()
207 if(iStatus == KErrNone)
209 switch(iService)
211 case CSdlAppServ::EAppSrvWaitDsa:
212 EpocSdlEnv::SetWaitDsa();
213 iReturnValue = EpocSdlEnv::IsDsaAvailable();
214 break;
216 case CSdlAppServ::EAppSrvStopThread:
217 if(gEpocEnv->iDsa != NULL)
218 gEpocEnv->iDsa->SetSuspend();
219 break;
221 case EAppSrvWindowPointerCursorMode:
222 iReturnValue = gEpocEnv->iDsa != NULL ? gEpocEnv->iDsa->Session().PointerCursorMode() : KErrNotReady;
223 break;
225 case EAppSrvDsaStatus:
226 if(gEpocEnv->iDsa != NULL)
227 gEpocEnv->iDsa->Stop();
228 iReturnValue = KErrNone;
229 break;
231 case EAppSrvNoop:
232 break;
234 default:
235 PANIC(KErrNotSupported);
236 break;
239 iStatus = KRequestPending;
240 iStatusPtr = &iStatus;
241 SetActive();
245 void CSdlAppServ::DoCancel()
247 TRequestStatus* s = &iStatus;
248 iAppThread.RequestComplete(s, KErrCancel);
251 CEventQueue& EpocSdlEnv::EventQueue()
253 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
254 return *gEpocEnv->iEventQueue;
257 int EpocSdlEnv::Argc()
259 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
260 return gEpocEnv->iArgc;
263 char** EpocSdlEnv::Argv()
265 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
266 return gEpocEnv->iArgv;
269 TBool EpocSdlEnv::IsDsaAvailable()
271 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
272 return gEpocEnv->iDsa != NULL && gEpocEnv->iDsa->IsDsaAvailable();
275 void EpocSdlEnv::WaitDsaAvailable()
277 gEpocEnv->iAppSrv->Request(CSdlAppServ::EAppSrvStopThread);
280 void EpocSdlEnv::Suspend()
282 if(gEpocEnv->iDsa != NULL)
284 gEpocEnv->iDsa->SetSuspend();
288 void EpocSdlEnv::SetWaitDsa()
290 if(!IsDsaAvailable())
292 if(gEpocEnv->iDsa != NULL)
293 gEpocEnv->iDsa->SetSuspend();
297 void EpocSdlEnv::Resume()
299 if(gEpocEnv->iDsa != NULL)
301 gEpocEnv->iDsa->Resume();
305 int EpocSdlEnv::AllocSurface(const TSize& aSize, TDisplayMode aMode)
307 return gEpocEnv->iDsa->AllocSurface(aSize, aMode);
310 void EpocSdlEnv::UnlockHwSurface()
312 gEpocEnv->iDsa->UnlockHwSurface();
315 TUint8* EpocSdlEnv::LockHwSurface()
317 return gEpocEnv->iDsa->LockHwSurface();
320 void EpocSdlEnv::UpdateSwSurface()
322 gEpocEnv->iDsa->UpdateSwSurface();
325 TBool EpocSdlEnv::AddUpdateRect(TUint8* aAddress, const TRect& aUpdateRect, const TRect& aRect)
327 return gEpocEnv->iDsa->AddUpdateRect(aAddress, aUpdateRect, aRect);
330 void EpocSdlEnv::Request(int aService)
332 __ASSERT_DEBUG(gEpocEnv != NULL, PANIC(KErrNotReady));
333 gEpocEnv->iAppSrv->Request(aService);
336 TDisplayMode EpocSdlEnv::DisplayMode()
338 return gEpocEnv->iDsa == NULL ? ENone : gEpocEnv->iDsa->DisplayMode();
341 TPointerCursorMode EpocSdlEnv::PointerMode()
343 return static_cast<TPointerCursorMode>(gEpocEnv->iAppSrv->RequestValue(CSdlAppServ::EAppSrvWindowPointerCursorMode));
346 int EpocSdlEnv::SetPalette(int aFirstcolor, int aColorCount, TUint32* aPalette)
348 return gEpocEnv->iDsa->SetPalette(aFirstcolor, aColorCount, aPalette);
351 void EpocSdlEnv::PanicMain(int aErr)
353 gEpocEnv->iAppSrv->PanicMain(aErr);
357 int EpocSdlEnv::AppendCleanupItem(const TSdlCleanupItem& aItem)
359 TRAPD(err, gEpocEnv->iCleanupItems->AppendL(aItem));
360 return err;
363 void EpocSdlEnv::RemoveCleanupItem(TAny* aItem)
365 for(int i = 0; i < gEpocEnv->iCleanupItems->Count(); i++)
367 if(gEpocEnv->iCleanupItems->At(i).iItem == aItem)
368 gEpocEnv->iCleanupItems->Delete(i);
372 void EpocSdlEnv::CleanupItems()
374 const TThreadId id = RThread().Id();
375 int last = gEpocEnv->iCleanupItems->Count() - 1;
376 int i;
378 for(i = last; i >= 0 ; i--)
380 TSdlCleanupItem& item = gEpocEnv->iCleanupItems->At(i);
381 if(item.iThread == id)
383 item.iThread = TThreadId(0);
384 item.iOperation(item.iItem);
388 last = gEpocEnv->iCleanupItems->Count() - 1;
390 for(i = last; i >= 0 ; i--)
392 TSdlCleanupItem& item = gEpocEnv->iCleanupItems->At(i);
393 if(item.iThread == TThreadId(0))
395 gEpocEnv->iCleanupItems->Delete(i);
400 void EpocSdlEnv::FreeSurface()
402 Request(CSdlAppServ::EAppSrvDsaStatus);
403 if(gEpocEnv->iDsa != NULL)
404 gEpocEnv->iDsa->Free();
407 void EpocSdlEnv::PanicMain(const TDesC& aInfo, int aErr)
409 gEpocEnv->iAppSrv->PanicMain(aInfo, aErr);
412 //Dsa is a low priority ao, it has to wait if its pending event, but ws
413 //event has been prioritized before it
414 //this is not called from app thread!
415 void EpocSdlEnv::WaitDeviceChange()
417 gEpocEnv->iAppSrv->RequestValue(CSdlAppServ::EAppSrvWaitDsa);
420 static TBool CheckSdl()
422 int isExit = ETrue;
423 RThread sdl;
424 if(sdl.Open(gEpocEnv->iId) == KErrNone)
426 if(sdl.ExitType() == EExitPending)
428 isExit = EFalse;
430 sdl.Close();
432 return isExit;
435 void EpocSdlEnvData::Free()
437 if(RThread().Id() == gEpocEnv->iId)
439 if(iDsa != NULL)
440 iDsa->Free();
441 return;
444 __ASSERT_ALWAYS(iArgv == NULL || CheckSdl(), PANIC(KErrNotReady));
447 void EpocSdlEnvData::Delete()
449 for(int i = 0; i <= iArgc; i++)
451 if(iArgv != NULL)
452 delete[] iArgv[i];
455 delete[] iArgv;
457 iArgv = NULL;
458 iArgc = 0;
460 delete iEventQueue;
462 if(iDsa != NULL)
463 iDsa->Free();
465 delete iDsa;
466 delete iAppSrv;
469 _LIT(KSDLMain, "SDLMain");
471 static int MainL()
473 gEpocEnv->iCleanupItems = new CArrayFixFlat<TSdlCleanupItem>(8);
475 char** envp=0;
476 /* !! process exits here if there is "exit()" in main! */
477 int ret = 0;
478 for(int i = 0; i < 6; i++)
480 void* f = (void*) gEpocEnv->iMain[i];
481 if(f != NULL)
483 switch(i)
485 case 0:
486 ret = ((mainfunc1)f)();
487 return ret;
489 case 3:
490 ((mainfunc1)f)();
491 return ret;
493 case 1:
494 ret = ((mainfunc2)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv());
495 return ret;
497 case 4:
498 ((mainfunc2)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv());
499 return ret;
501 case 2:
502 ret = ((mainfunc3)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv(), envp);
503 return ret;
505 case 5:
506 ((mainfunc3)f)(EpocSdlEnv::Argc(), EpocSdlEnv::Argv(), envp);
507 return ret;
511 PANIC(KErrNotFound);
512 return 0;
515 static int DoMain(TAny* /*aParam*/)
517 TBool fbsconnected = EFalse;
519 gEpocEnv->iAppSrv->Init();
521 // Call stdlib main
522 int ret = 0;
524 TRAPD(err, err = MainL());
526 // Free resources and return
527 EpocSdlEnv::CleanupItems();
529 gEpocEnv->iCleanupItems->Reset();
530 delete gEpocEnv->iCleanupItems;
531 gEpocEnv->iCleanupItems = NULL;
533 gEpocEnv->Free(); //free up in thread resources
535 if(fbsconnected)
536 RFbsSession::Disconnect();
538 if(gEpocEnv->iCallerStatus != NULL)
540 User::RequestComplete(gEpocEnv->iCallerStatus, err);
541 return 0;
543 else
545 return err == KErrNone ? ret : err;
549 CSDL::~CSDL()
551 gEpocEnv->Free();
552 gEpocEnv->Delete();
554 delete gEpocEnv;
555 gEpocEnv = NULL;
558 CSDL* CSDL::NewL()
560 __ASSERT_ALWAYS(gEpocEnv == NULL, PANIC(KErrAlreadyExists));
561 gEpocEnv = new EpocSdlEnvData;
562 Mem::FillZ(gEpocEnv, sizeof(EpocSdlEnvData));
564 gEpocEnv->iEventQueue = new CEventQueue();
565 gEpocEnv->iAppSrv = new CSdlAppServ();
567 CSDL* sdl = new CSDL();
569 gEpocEnv->iSdl = sdl;
571 return sdl;
574 void CSDL::SetContainerWindowL(RWindow& aWindow, RWsSession& aSession, CWsScreenDevice& aDevice)
576 if(gEpocEnv->iDsa == NULL)
577 gEpocEnv->iDsa = CDsa::CreateL(aSession);
578 gEpocEnv->iDsa->ConstructL(aWindow, aDevice);
581 int EpocSdlEnv::ApplyGlesDsa()
583 CDsa* dsa = NULL;
584 TRAPD(err, dsa = gEpocEnv->iDsa->CreateGlesDsaL());
585 gEpocEnv->iDsa = dsa;
586 return err;
589 RWindow* EpocSdlEnv::Window()
591 return gEpocEnv->iDsa->Window();
594 void EpocSdlEnv::UpdateWholeScreen(bool val)
596 gEpocEnv->iDsa->m_updateWholeScreen = val;
599 bool EpocSdlEnv::GetUpdateWholeScreen()
601 return gEpocEnv->iDsa->m_updateWholeScreen;
604 void EpocSdlEnv::SetOrientation(CAknAppUi::TAppUiOrientation orientation, const TSize& aSize, TDisplayMode aMode)
606 gEpocEnv->iWaitingForOrientationChange = true;
607 gEpocEnv->iSize = aSize;
608 gEpocEnv->iMode = aMode;
610 TRAPD(err, static_cast<CAknAppUi*>(CEikonEnv::Static()->EikAppUi())->SetOrientationL(orientation));
613 TThreadId CSDL::CallMainL(const TMainFunc& aFunc, TRequestStatus* const aStatus, const CDesC8Array* const aArg)
615 ASSERT(gEpocEnv != NULL);
616 gEpocEnv->iMain = aFunc;
617 const TBool args = aArg != NULL;
619 if(gEpocEnv->iArgv != NULL)
620 User::Leave(KErrAlreadyExists);
622 gEpocEnv->iArgc = args ? aArg->Count() + 1 : 0;
623 gEpocEnv->iArgv = new char*[gEpocEnv->iArgc + 2];
625 int k = 0;
626 const TFileName processName = RProcess().FileName();
627 const int len = processName.Length();
628 gEpocEnv->iArgv[k] = new char[len + 1];
629 Mem::Copy(gEpocEnv->iArgv[k], processName.Ptr(), len);
630 gEpocEnv->iArgv[k][len] = 0;
632 for(int i = 0; args && (i < aArg->Count()); i++)
634 k++;
635 const int len = aArg->MdcaPoint(i).Length();
636 gEpocEnv->iArgv[k] = new char[len + 1];
637 Mem::Copy(gEpocEnv->iArgv[k], aArg->MdcaPoint(i).Ptr(), len);
638 gEpocEnv->iArgv[k][len] = 0;
641 gEpocEnv->iArgv[k + 1] = NULL;
643 gEpocEnv->iAppSrv->ConstructL();
645 // for handling volume up/down keys
646 CRemConInterfaceSelector *iSelector = CRemConInterfaceSelector::NewL();
647 CRemConCoreApiTarget::NewL( *iSelector, *this );
648 iSelector->OpenTargetL();
650 gEpocEnv->iCallerStatus = aStatus;
651 if(aStatus != NULL)
652 *aStatus = KRequestPending;
653 gEpocEnv->iId = RThread().Id();
654 // when priority is not lowered screen updates much more frequently, which
655 // may be undesired, for example in case of openttd's generating world dialog
656 RThread().SetPriority(EPriorityLess);
657 DoMain( NULL );
659 return gEpocEnv->iId;
662 void CSDL::AppendWsEvent(const TWsEvent& aEvent)
664 EpocSdlEnv::EventQueue().Append(aEvent);
667 void CSDL::SDLPanic(const TDesC& aInfo, int aErr)
669 EpocSdlEnv::PanicMain(aInfo, aErr);
672 int CSDL::GetSDLCode(int aScanCode)
674 if(aScanCode < 0)
675 return MAX_SCANCODE;
676 if(aScanCode >= MAX_SCANCODE)
677 return -1;
678 return KeyMap()[aScanCode];
681 int CSDL::SDLCodesCount() const
683 return MAX_SCANCODE;
686 void CSDL::ResetSDLCodes()
688 ResetKeyMap();
691 int CSDL::SetSDLCode(int aScanCode, int aSDLCode)
693 const int current = GetSDLCode(aScanCode);
694 if(aScanCode >= 0 && aScanCode < MAX_SCANCODE)
695 KeyMap()[aScanCode] = static_cast<SDLKey>(aSDLCode);
696 return current;
699 void CSDL::Resume()
701 EpocSdlEnv::Resume();
704 void CSDL::Suspend()
706 if(gEpocEnv->iDsa != NULL)
707 gEpocEnv->iDsa->DoStop();
710 void CSDL::Resize()
712 if(gEpocEnv->iWaitingForOrientationChange)
714 EpocSdlEnv::AllocSurface(gEpocEnv->iSize, gEpocEnv->iMode);
715 gEpocEnv->iWaitingForOrientationChange = false;
717 else
719 TSize size = gEpocEnv->iDsa->Window()->Size();
720 SDL_PrivateResize(size.iWidth, size.iHeight);
724 CSDL::CSDL()
727 void CSDL::MrccatoCommand(TRemConCoreApiOperationId aOperationId, TRemConCoreApiButtonAction aButtonAct)
729 if(aButtonAct != ERemConCoreApiButtonClick)
730 return;
732 TWsEvent event;
733 event.SetType(EEventKey);
734 event.SetTimeNow();
736 switch(aOperationId)
738 case ERemConCoreApiVolumeDown:
739 event.Key()->iScanCode = EStdKeyDecVolume;
740 event.SetType(EEventKeyDown);
741 AppendWsEvent(event);
742 event.SetType(EEventKeyUp);
743 AppendWsEvent(event);
744 break;
746 case ERemConCoreApiVolumeUp:
747 event.Key()->iScanCode = EStdKeyIncVolume;
748 event.SetType(EEventKeyDown);
749 AppendWsEvent(event);
750 event.SetType(EEventKeyUp);
751 AppendWsEvent(event);
752 break;
754 default:
755 break;
759 void* SDL_LoadObject(const char *sofile)
761 RLibrary* lib = new RLibrary();
762 if(lib == NULL)
763 return NULL;
764 TFileName name;
765 name.Copy(TPtrC8((const TUint8*)sofile));
766 if(KErrNone == lib->Load(name))
767 return lib;
768 delete lib;
769 return NULL;
772 void* SDL_LoadFunction(void *handle, const char *name)
774 TLex8 v((const TUint8*)(name));
775 int ord;
777 if(KErrNone != v.Val(ord))
778 return NULL;
780 const RLibrary* lib = reinterpret_cast<RLibrary*>(handle);
781 TLibraryFunction f = lib->Lookup(ord);
782 return (void*)(f);
785 void SDL_UnloadObject(void *handle)
787 RLibrary* lib = reinterpret_cast<RLibrary*>(handle);
788 lib->Close();
789 delete lib;