1 /*******************************************************************
\r
5 * Author: Peter van Sebille (peter@yipton.net)
\r
7 * Modified/adapted for picodriveN by notaz, 2006
\r
9 * (c) Copyright 2006, notaz
\r
10 * (c) Copyright 2002, Peter van Sebille
\r
11 * All Rights Reserved
\r
13 *******************************************************************/
\r
16 // #include "picodriven.mbg" // bitmap identifiers
\r
17 #include "picodriven.rsg"
\r
19 #include <qbtselectdlg.h>
\r
20 //#include <gulutil.h>
\r
21 //#include <bautils.h>
\r
22 #include <eikmenub.h> // CEikMenuBar
\r
23 #include <apgtask.h> // TApaSystemEvent
\r
25 #include "Dialogs.h"
\r
28 CApaDocument* CPicolApplication::CreateDocumentL()
\r
30 return new (ELeave) CPicolDocument(*this);
\r
34 CPicolDocument::CPicolDocument(CEikApplication& aApp)
\r
35 : CEikDocument(aApp)
\r
39 CPicolDocument::~CPicolDocument()
\r
43 CEikAppUi* CPicolDocument::CreateAppUiL()
\r
45 return new(ELeave) CPicolAppUi;
\r
49 ////////////////////////////////////////////////////////////////
\r
51 // class CPicolAppUi
\r
53 ////////////////////////////////////////////////////////////////
\r
55 CPicolAppUi::CPicolAppUi()
\r
56 : iCurrentLConfig(iCurrentConfig)
\r
58 // set default config
\r
59 Mem::FillZ(&iCurrentConfig, sizeof(iCurrentConfig));
\r
60 iCurrentConfig.iFlags = 1; // use_sram
\r
61 iCurrentConfig.iFrameskip = TPicoConfig::PFSkipAuto;
\r
62 iCurrentConfig.iScreenRotation = TPicoConfig::PRot90;
\r
65 CPicolAppUi::~CPicolAppUi()
\r
68 DeregisterView(*iFOView);
\r
70 DeregisterView(*iFCView);
\r
74 void CPicolAppUi::ConstructL()
\r
79 iCurrentLConfig.Load();
\r
81 iAppView=new(ELeave) CEPicolAppView;
\r
82 iAppView->ConstructL(ClientRect());
\r
84 iFOView=new(ELeave) CPicolFOView(*iAppView);
\r
85 RegisterViewL(*iFOView);
\r
86 iFCView=new(ELeave) CPicolFCView(*iAppView);
\r
87 RegisterViewL(*iFCView);
\r
91 void CPicolAppUi::HandleCommandL(TInt aCommand)
\r
93 TInt oldFrameskip = iCurrentConfig.iFrameskip;
\r
96 // give time for config dialog destruction
\r
97 if(iAfterConfigDialog) {
\r
98 iAfterConfigDialog = EFalse;
\r
99 TTime now; now.UniversalTime();
\r
100 if(now.MicroSecondsFrom(iConfigDialogClosed).Int64().Low() < 2500*1000)
\r
101 User::After(2500*1000-now.MicroSecondsFrom(iConfigDialogClosed).Int64().Low());
\r
106 case EEikCmdPicoLoadState:
\r
108 CEikonEnv::Static()->BusyMsgL(_L("Loading State"));
\r
109 res = ss.SendReceive(PicoMsgLoadState, 0);
\r
110 CEikonEnv::Static()->BusyMsgCancel();
\r
111 // emu doesn't start to run if load fails, so we can display this
\r
112 if(res) CEikonEnv::Static()->InfoMsg(_L("Load Failed"));
\r
116 case EEikCmdPicoSaveState:
\r
118 CEikonEnv::Static()->BusyMsgL(_L("Saving State"));
\r
119 res = ss.SendReceive(PicoMsgSaveState, 0);
\r
120 CEikonEnv::Static()->BusyMsgCancel();
\r
121 if(res) CEikonEnv::Static()->InfoMsg(_L("Save Failed"));
\r
125 case EEikCmdPicoLoadROM:
\r
126 DisplayOpenROMDialogL();
\r
129 case EEikCmdPicoResume:
\r
130 ss.Send(PicoMsgResume, 0);
\r
131 iEmuRunning = ETrue;
\r
134 case EEikCmdPicoReset:
\r
135 ss.Send(PicoMsgReset, 0);
\r
136 iEmuRunning = ETrue;
\r
139 case EEikCmdPicoKeys:
\r
140 if(!iGameRunner) RunGameL();
\r
141 ss.Send(PicoMsgKeys, 0);
\r
142 iEmuRunning = ETrue;
\r
145 case EEikCmdPicoSettings:
\r
146 DisplayConfigDialogL();
\r
149 case EEikCmdHelpAbout: // EEikCmdPicoAbout:
\r
150 DisplayAboutDialogL();
\r
153 // standard identifier must be used here, TApaTask::EndTask() and probably others send it
\r
154 case EEikCmdExit: // EEikCmdPicoExit:
\r
157 iExitForcer = CExitForcer::NewL(*this, 2000);
\r
158 ss.Send(PicoMsgQuit, 0);
\r
160 iCurrentLConfig.Save();
\r
161 DEBUGPRINT(_L("[app] Exit (menu)"));
\r
167 case EEikCmdPicoFrameskipAuto:
\r
168 iCurrentConfig.iFrameskip = TPicoConfig::PFSkipAuto;
\r
171 case EEikCmdPicoFrameskip0:
\r
172 iCurrentConfig.iFrameskip = TPicoConfig::PFSkip0;
\r
175 case EEikCmdPicoFrameskip1:
\r
176 iCurrentConfig.iFrameskip = 1;
\r
179 case EEikCmdPicoFrameskip2:
\r
180 iCurrentConfig.iFrameskip = 2;
\r
183 case EEikCmdPicoFrameskip4:
\r
184 iCurrentConfig.iFrameskip = 4;
\r
187 case EEikCmdPicoFrameskip8:
\r
188 iCurrentConfig.iFrameskip = 8;
\r
191 case EEikCmdPicoDebugKillEmu:
\r
193 iExitForcer = CExitForcer::NewL(*this, 4000);
\r
194 ss.Send(PicoMsgQuit, 0);
\r
198 case EEikCmdPicoDebugInfo:
\r
200 DisplayDebugDialogL();
\r
204 // send config update if needed
\r
205 if(iCurrentConfig.iFrameskip != oldFrameskip)
\r
210 void CPicolAppUi::HandleSystemEventL(const TWsEvent& aEvent)
\r
212 TApaSystemEvent event;
\r
213 event = *(TApaSystemEvent*)aEvent.EventData();
\r
215 if(event == EApaSystemEventBroughtToForeground) // application brought to foreground
\r
217 DEBUGPRINT(_L("[app] EApaSystemEventBroughtToForeground, iEmuRunning=%i"), iEmuRunning);
\r
218 // we might have missed flip open event (when moved to background),
\r
219 // so make sure we have correct view active
\r
220 if(iCoeEnv->ScreenDevice()->CurrentScreenMode() == EScreenModeFlipOpen) {
\r
221 ActivateViewL(TVwsViewId(KUidPicolApp, KUidPicolFOView));
\r
225 if(event == EApaSystemEventShutdown)
\r
227 DEBUGPRINT(_L("[app] EApaSystemEventShutdown"));
\r
230 CEikAppUi::HandleSystemEventL(aEvent);
\r
234 // called just before the menu is shown
\r
235 void CPicolAppUi::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane)
\r
237 if(aResourceId == R_APP_EMU_MENU) {
\r
238 TBool dimmed = !iGameRunner || !iROMLoaded;
\r
239 aMenuPane->SetItemDimmed(EEikCmdPicoLoadState, dimmed);
\r
240 aMenuPane->SetItemDimmed(EEikCmdPicoSaveState, dimmed);
\r
241 aMenuPane->SetItemDimmed(EEikCmdPicoResume, dimmed);
\r
242 aMenuPane->SetItemDimmed(EEikCmdPicoReset, dimmed);
\r
243 } else if(aResourceId == R_APP_FRAMESKIP_MENU) {
\r
244 TInt itemToCheck = EEikCmdPicoFrameskipAuto;
\r
245 switch(iCurrentConfig.iFrameskip) {
\r
246 case 0: itemToCheck = EEikCmdPicoFrameskip0; break;
\r
247 case 1: itemToCheck = EEikCmdPicoFrameskip1; break;
\r
248 case 2: itemToCheck = EEikCmdPicoFrameskip2; break;
\r
249 case 4: itemToCheck = EEikCmdPicoFrameskip4; break;
\r
250 case 8: itemToCheck = EEikCmdPicoFrameskip8; break;
\r
252 aMenuPane->SetItemButtonState(itemToCheck, EEikMenuItemSymbolOn);
\r
257 void CPicolAppUi::DisplayAboutDialogL()
\r
259 CEikDialog* dialog = new(ELeave) CAboutDialog;
\r
260 TInt iButtonRes = dialog->ExecuteLD(R_DIALOG_ABOUT);
\r
261 if(iButtonRes == EEikBidYes) {
\r
262 CCreditsDialog *creditsDialog = new (ELeave) CCreditsDialog();
\r
263 creditsDialog->iMessageResourceID = R_TBUF_CREDITS;
\r
264 creditsDialog->ExecuteLD(R_DIALOG_CREDITS);
\r
269 void CPicolAppUi::DisplayOpenROMDialogL()
\r
272 TFileName file(iCurrentLConfig.iLastROMFile);
\r
273 CEikDialog* dialog = new(ELeave) CEikFileOpenDialog(&file);
\r
274 //((CEikFileOpenDialog *)dialog)->SetRequiredExtension(&ext);
\r
276 if(dialog->ExecuteLD(R_EIK_DIALOG_FILE_OPEN) == EEikBidOk) {
\r
277 CEikonEnv::Static()->BusyMsgL(_L("Loading ROM"));
\r
279 // start emu process if it is not running
\r
280 if(!iGameRunner) RunGameL();
\r
281 iROMLoaded = EFalse;
\r
283 TBuf8<KMaxFileName> file8;
\r
285 TAny *p[KMaxMessageArguments];
\r
286 p[0]= (TAny*)(&file8);
\r
287 TInt res = ss.SendReceive(PicoMsgLoadROM, &p[0]);
\r
289 CEikonEnv::Static()->BusyMsgCancel();
\r
292 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to open file."));
\r
294 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate memory."));
\r
296 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("The file you selected is not a game ROM."));
\r
298 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("No game ROMs found in zipfile."));
\r
300 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed while unzipping ROM."));
\r
302 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to send request to emu process."));
\r
304 iROMLoaded = ETrue;
\r
305 iEmuRunning = ETrue;
\r
308 // sound errors which leave ROM loaded
\r
310 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to allocate sound buffer, disabled sound."));
\r
312 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to start soundsystem, disabled sound."));
\r
313 if(res == 6 || res == 7) iCurrentConfig.iFlags &= ~4;
\r
315 iCurrentLConfig.iLastROMFile.Copy(file);
\r
320 void CPicolAppUi::DisplayConfigDialogL()
\r
322 CPicoConfigDialog* configDialog = new(ELeave)CPicoConfigDialog(iCurrentConfig, iCurrentLConfig);
\r
323 configDialog->ExecuteLD(R_PICO_CONFIG);
\r
328 iCurrentLConfig.Save();
\r
330 // configDialog seems to be actually destroyed later after returning,
\r
331 // and this usually happens just after resuming game and causes emu slowdowns :/
\r
332 iAfterConfigDialog = ETrue;
\r
333 iConfigDialogClosed.UniversalTime();
\r
337 void CPicolAppUi::DisplayDebugDialogL()
\r
339 // first get our debug info
\r
342 TAny *p[KMaxMessageArguments];
\r
343 TPtr8 descr((TUint8*) dtxt, sizeof(dtxt));
\r
344 p[0]= (TAny*)(&descr);
\r
345 ss.SendReceive(PicoMsgRetrieveDebugStr, &p[0]);
\r
347 CEikDialog* dialog = new(ELeave) CDebugDialog(dtxt);
\r
348 dialog->ExecuteLD(R_DIALOG_DEBUG);
\r
352 void CPicolAppUi::SendConfig()
\r
356 TAny *p[KMaxMessageArguments];
\r
357 TPtrC8 descr((TUint8*) &iCurrentConfig, sizeof(iCurrentConfig));
\r
358 p[0]= (TAny*)(&descr);
\r
359 ss.Send(PicoMsgConfigChange, &p[0]);
\r
364 // get config from emu proc
\r
365 void CPicolAppUi::RetrieveConfig()
\r
367 // ask to configure keys and receive new config
\r
368 TAny *p[KMaxMessageArguments];
\r
369 TPtr8 descr((TUint8*) &iCurrentConfig, sizeof(iCurrentConfig));
\r
370 p[0]= (TAny*)(&descr);
\r
371 ss.SendReceive(PicoMsgRetrieveConfig, &p[0]);
\r
373 iCurrentLConfig.Save();
\r
377 void CPicolAppUi::NotifyEmuDeath()
\r
381 DEBUGPRINT(_L("[app] Exit (NotifyEmuDeath)"));
\r
382 iCurrentLConfig.Save();
\r
389 void CPicolAppUi::NotifyForcedExit()
\r
391 DEBUGPRINT(_L("[app] Exit (NotifyForcedExit)"));
\r
398 TBool CPicolAppUi::EmuRunning() const
\r
400 return iEmuRunning;
\r
404 void CPicolAppUi::StopGame()
\r
406 // in case we have busyMsg and process crashes
\r
407 CEikonEnv::Static()->BusyMsgCancel();
\r
410 if(iGameRunner) delete iGameRunner;
\r
411 iGameRunner = NULL;
\r
412 if(iExitForcer) delete iExitForcer;
\r
413 iExitForcer = NULL;
\r
414 if(iThreadWatcher1) delete iThreadWatcher1;
\r
415 iThreadWatcher1 = NULL;
\r
416 iROMLoaded = EFalse;
\r
417 iEmuRunning = EFalse;
\r
421 void CPicolAppUi::RunGameL()
\r
423 TInt res = KErrNone;
\r
425 // do one connection attemt to emu and ask it to quit if we succeed
\r
426 res = ss.Connect();
\r
427 if(res == KErrNone) {
\r
428 ss.Send(PicoMsgQuit, 0);
\r
432 iGameRunner = CGameRunner::NewL(*this);
\r
434 // Connect to the server
\r
435 // we don't want to do complex asynchronous stuff here, so we just
\r
436 // wait and do several connection attempts
\r
437 User::After(200000);
\r
438 for(TInt attempt=0; attempt < 10; attempt++) {
\r
439 res = ss.Connect();
\r
440 if(res == KErrNone) break;
\r
441 User::After(200000);
\r
444 if(res != KErrNone) {
\r
445 CEikonEnv::Static()->BusyMsgCancel();
\r
446 CEikonEnv::Static()->InfoWinL(_L("Error"), _L("Failed to communicate with the emulation process."));
\r
452 // now we are successfully connected, that means emu process' helper-communication thread is running.
\r
453 // we have to keep an eye on it too, because if it crashes, symbian OS leaves it's process
\r
454 // alive, but it becomes useless without it's communication thread so we have to detect it's death.
\r
455 iThreadWatcher1 = CThreadWatcher::NewL(*this, KServerName);
\r
457 // send initial config
\r
463 void CPicolAppUi::HandleScreenDeviceChangedL()
\r
465 // does not receive when emu is in foreground
\r
466 if(iCoeEnv->ScreenDevice()->CurrentScreenMode() == 0) { // flip open
\r
468 //iCoeEnv->BringOwnerToFront();
\r
471 // ss.Send(PicoMsgFlipChange, 0);
\r
475 void CPicolAppUi::HandleApplicationSpecificEventL(TInt aType, const TWsEvent& aEvent)
\r
477 DEBUGPRINT(_L("[app] event from server: %i"), aEvent.Type());
\r
479 switch (aEvent.Type())
\r
481 case EEventKeyCfgDone:
\r
485 case EEventGamePaused:
\r
486 iEmuRunning = EFalse;
\r
491 ////////////////////////////////////////////////////////////////
\r
493 // class CEPicolAppView
\r
495 ////////////////////////////////////////////////////////////////
\r
497 void CEPicolAppView::ConstructL(const TRect& aRect)
\r
504 * Load background image
\r
507 TBuf<1> name = _L("*");
\r
508 TRAPD(err, iBgImage = CEikonEnv::Static()->CreateBitmapL(name, EMbmEdoomDoom));
\r
511 iImagePosition.iX = (aRect.Size().iWidth - iBgImage->SizeInPixels().iWidth) / 2;
\r
512 iImagePosition.iY = (aRect.Size().iHeight - iBgImage->SizeInPixels().iHeight) / 2;
\r
517 CEPicolAppView::~CEPicolAppView()
\r
519 //if (iBgImage) delete iBgImage;
\r
523 void CEPicolAppView::Draw(const TRect& aRect) const
\r
525 CWindowGc& gc = SystemGc();
\r
529 // gc.DrawBitmap(iImagePosition, iBgImage);
\r
530 // DrawUtils::ClearBetweenRects(gc, Rect(), TRect(iImagePosition, iBgImage->SizeInPixels()));
\r
533 gc.Clear();//aRect);
\r
537 ////////////////////////////////////////////////////////////////
\r
539 // class CPicolViewBase
\r
541 ////////////////////////////////////////////////////////////////
\r
543 void CPicolViewBase::ViewActivatedL(const TVwsViewId& /*aPrevViewId*/, TUid /*aCustomMessageId*/, const TDesC8& /*aCustomMessage*/)
\r
545 TPixelsAndRotation sizeAndRotation;
\r
546 CEikonEnv::Static()->ScreenDevice()->GetDefaultScreenSizeAndRotation(sizeAndRotation);
\r
547 CEikonEnv::Static()->ScreenDevice()->SetScreenSizeAndRotation(sizeAndRotation);
\r
548 //iAppViewCtl.MakeVisible(ETrue);
\r
551 void CPicolViewBase::ViewDeactivated()
\r
553 //iAppViewCtl.MakeVisible(EFalse);
\r
557 ////////////////////////////////////////////////////////////////
\r
559 // class CPicolFOView
\r
561 ////////////////////////////////////////////////////////////////
\r
563 TVwsViewId CPicolFOView::ViewId() const
\r
565 return TVwsViewId(KUidPicolApp, KUidPicolFOView);
\r
568 TVwsViewIdAndMessage CPicolFOView::ViewScreenDeviceChangedL()
\r
570 // only handle change to FC mode when emu process is running
\r
571 if(static_cast<CPicolAppUi*>(CEikonEnv::Static()->AppUi())->EmuRunning())
\r
572 return TVwsViewIdAndMessage(TVwsViewId(KUidPicolApp, KUidPicolFCView));
\r
573 else return MCoeView::ViewScreenDeviceChangedL();
\r
576 TBool CPicolFOView::ViewScreenModeCompatible(TInt aScreenMode)
\r
578 return (aScreenMode == EScreenModeFlipOpen);
\r
581 void CPicolFOView::ViewActivatedL(const TVwsViewId& aPrevViewId, TUid aCustomMessageId, const TDesC8& aCustomMessage)
\r
583 DEBUGPRINT(_L("[app] FO"));
\r
584 CPicolViewBase::ViewActivatedL(aPrevViewId, aCustomMessageId, aCustomMessage);
\r
585 CEikonEnv::Static()->AppUiFactory()->MenuBar()->MakeVisible(ETrue);
\r
587 iAppViewCtl.SetRect(static_cast<CEikAppUi*>(CEikonEnv::Static()->AppUi())->ClientRect());
\r
591 ////////////////////////////////////////////////////////////////
\r
593 // class CPicolFCView
\r
595 ////////////////////////////////////////////////////////////////
\r
597 TVwsViewId CPicolFCView::ViewId() const
\r
599 return TVwsViewId(KUidPicolApp, KUidPicolFCView);
\r
602 TVwsViewIdAndMessage CPicolFCView::ViewScreenDeviceChangedL()
\r
604 return TVwsViewIdAndMessage(TVwsViewId(KUidPicolApp, KUidPicolFOView));
\r
607 TBool CPicolFCView::ViewScreenModeCompatible(TInt aScreenMode)
\r
609 return (aScreenMode == EScreenModeFlipClosed);
\r
612 void CPicolFCView::ViewActivatedL(const TVwsViewId& aPrevViewId, TUid aCustomMessageId, const TDesC8& aCustomMessage)
\r
614 DEBUGPRINT(_L("[app] FC"));
\r
615 CPicolViewBase::ViewActivatedL(aPrevViewId, aCustomMessageId, aCustomMessage);
\r
616 CEikonEnv::Static()->AppUiFactory()->MenuBar()->MakeVisible(EFalse);
\r
617 //iAppViewCtl.ChangeLayout(ETrue);
\r
618 iAppViewCtl.SetRect(CEikonEnv::Static()->ScreenDevice()->SizeInPixels());
\r
622 ////////////////////////////////////////////////////////////////
\r
626 ////////////////////////////////////////////////////////////////
\r
628 GLDEF_C TInt E32Dll(TDllReason)
\r
634 EXPORT_C CApaApplication* NewApplication()
\r
636 return new CPicolApplication;
\r
640 TUid CPicolApplication::AppDllUid() const
\r
642 return KUidPicolApp;
\r