1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
21 #include "Common.h" // Common
23 #if defined HAVE_X11 && HAVE_X11
27 #include "CPUDetect.h"
32 #include "Host.h" // Core
33 #include "PluginManager.h"
35 #include "Globals.h" // Local
37 #include "ConfigManager.h"
38 #include "CodeWindow.h"
39 #include "LogWindow.h"
40 #include "JitWindow.h"
41 #include "ExtendedTrace.h"
42 #include "BootManager.h"
48 IMPLEMENT_APP(DolphinApp
)
50 BEGIN_EVENT_TABLE(DolphinApp
, wxApp
)
51 EVT_TIMER(wxID_ANY
, DolphinApp::AfterInit
)
54 #include <wx/stdpaths.h>
55 bool wxMsgAlert(const char*, const char*, bool, int);
57 CFrame
* main_frame
= NULL
;
60 //Has no error handling.
61 //I think that if an error occurs here there's no way to handle it anyway.
62 LONG WINAPI
MyUnhandledExceptionFilter(LPEXCEPTION_POINTERS e
) {
63 //EnterCriticalSection(&g_uefcs);
66 fopen_s(&file
, "exceptioninfo.txt", "a");
67 fseek(file
, 0, SEEK_END
);
69 //etfprint(file, g_buildtime);
70 //etfprint(file, "\n");
71 //dumpCurrentDate(file);
72 etfprintf(file
, "Unhandled Exception\n Code: 0x%08X\n",
73 e
->ExceptionRecord
->ExceptionCode
);
75 STACKTRACE2(file
, e
->ContextRecord
->Eip
, e
->ContextRecord
->Esp
, e
->ContextRecord
->Ebp
);
77 STACKTRACE2(file
, e
->ContextRecord
->Rip
, e
->ContextRecord
->Rsp
, e
->ContextRecord
->Rbp
);
82 //LeaveCriticalSection(&g_uefcs);
83 return EXCEPTION_CONTINUE_SEARCH
;
87 // The `main program' equivalent that creates the main window and return the main frame
89 bool DolphinApp::OnInit()
91 // Declarations and definitions
92 bool UseDebugger
= false;
93 bool BatchMode
= false;
94 bool UseLogger
= false;
95 bool selectVideoPlugin
= false;
96 bool selectAudioPlugin
= false;
97 bool selectWiimotePlugin
= false;
99 wxString videoPluginFilename
;
100 wxString audioPluginFilename
;
101 wxString wiimotePluginFilename
;
103 #if wxUSE_CMDLINE_PARSER // Parse command lines
104 #if wxCHECK_VERSION(2, 9, 0)
105 wxCmdLineEntryDesc cmdLineDesc
[] =
108 wxCMD_LINE_SWITCH
, "h", "help", "Show this help message",
109 wxCMD_LINE_VAL_NONE
, wxCMD_LINE_OPTION_HELP
112 wxCMD_LINE_SWITCH
, "d", "debugger", "Opens the debugger"
115 wxCMD_LINE_SWITCH
, "l", "logger", "Opens the logger"
118 wxCMD_LINE_OPTION
, "e", "exec", "Loads the specified file (DOL, ELF, WAD, GCM, ISO)",
119 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
122 wxCMD_LINE_SWITCH
, "b", "batch", "Exit Dolphin with emulator"
125 wxCMD_LINE_OPTION
, "V", "video_plugin","Specify a video plugin",
126 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
129 wxCMD_LINE_OPTION
, "A", "audio_plugin","Specify an audio plugin",
130 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
133 wxCMD_LINE_OPTION
, "W", "wiimote_plugin","Specify a wiimote plugin",
134 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
141 wxCmdLineEntryDesc cmdLineDesc
[] =
144 wxCMD_LINE_SWITCH
, _("h"), _("help"),
145 wxT("Show this help message"),
146 wxCMD_LINE_VAL_NONE
, wxCMD_LINE_OPTION_HELP
149 wxCMD_LINE_SWITCH
, _("d"), _("debugger"), wxT("Opens the debugger")
152 wxCMD_LINE_SWITCH
, _("l"), _("logger"), wxT("Opens the logger")
155 wxCMD_LINE_OPTION
, _("e"), _("exec"), wxT("Loads the specified file (DOL, ELF, WAD, GCM, ISO)"),
156 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
159 wxCMD_LINE_SWITCH
, _("b"), _("batch"), wxT("Exit Dolphin with emulator")
162 wxCMD_LINE_OPTION
, _("V"), _("video_plugin"), wxT("Specify a video plugin"),
163 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
166 wxCMD_LINE_OPTION
, _("A"), _("audio_plugin"), wxT("Specify an audio plugin"),
167 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
170 wxCMD_LINE_OPTION
, _("W"), _("wiimote_plugin"), wxT("Specify a wiimote plugin"),
171 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
178 // Gets the command line parameters
179 wxCmdLineParser
parser(cmdLineDesc
, argc
, argv
);
181 if (parser
.Parse() != 0)
185 #if wxCHECK_VERSION(2, 9, 0)
186 UseDebugger
= parser
.Found("debugger");
187 UseLogger
= parser
.Found("logger");
188 LoadFile
= parser
.Found("exec", &FileToLoad
);
189 BatchMode
= parser
.Found("batch");
191 UseDebugger
= parser
.Found(wxT("debugger"));
192 UseLogger
= parser
.Found(wxT("logger"));
193 LoadFile
= parser
.Found(wxT("exec"), &FileToLoad
);
194 BatchMode
= parser
.Found(wxT("batch"));
197 #if wxCHECK_VERSION(2, 9, 0)
198 selectVideoPlugin
= parser
.Found("video_plugin", &videoPluginFilename
);
199 selectAudioPlugin
= parser
.Found("audio_plugin", &audioPluginFilename
);
200 selectWiimotePlugin
= parser
.Found("wiimote_plugin", &wiimotePluginFilename
);
202 selectVideoPlugin
= parser
.Found(wxT("video_plugin"), &videoPluginFilename
);
203 selectAudioPlugin
= parser
.Found(wxT("audio_plugin"), &audioPluginFilename
);
204 selectWiimotePlugin
= parser
.Found(wxT("wiimote_plugin"), &wiimotePluginFilename
);
206 #endif // wxUSE_CMDLINE_PARSER
208 #if defined _DEBUG && defined _WIN32
209 int tmpflag
= _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG
);
210 tmpflag
|= _CRTDBG_DELAY_FREE_MEM_DF
;
211 _CrtSetDbgFlag(tmpflag
);
214 // Register message box handler
216 RegisterMsgAlertHandler(&wxMsgAlert
);
219 // "ExtendedTrace" looks freakin dangerous!!!
221 EXTENDEDTRACEINITIALIZE(".");
222 SetUnhandledExceptionFilter(&MyUnhandledExceptionFilter
);
225 // TODO: if First Boot
228 PanicAlert("Hi,\n\nDolphin requires that your CPU has support for SSE2 extensions.\n"
229 "Unfortunately your CPU does not support them, so Dolphin will not run.\n\n"
234 #if ! defined(__APPLE__) && ! defined(__linux__)
235 // Keep the user config dir free unless user wants to save the working dir
236 if (!File::Exists((std::string(File::GetUserPath(D_CONFIG_IDX
)) + "portable").c_str()))
239 sprintf(tmp
, "%s/.dolphin%swd", (const char*)wxStandardPaths::Get().GetUserConfigDir().mb_str(),
245 FILE* workingDir
= fopen(tmp
, "r");
248 if (PanicYesNo("Dolphin has not been configured with an install location,\nKeep Dolphin portable?"))
250 FILE* portable
= fopen((std::string(File::GetUserPath(D_CONFIG_IDX
)) + "portable").c_str(), "w");
253 PanicAlert("Portable Setting could not be saved\n Are you running Dolphin from read only media or from a directory that dolphin is not located in?");
263 sprintf(CWD
, "%s", (const char*)wxGetCwd().mb_str());
264 if (PanicYesNo("Set install location to:\n %s ?", CWD
))
266 FILE* workingDirF
= fopen(tmp
, "w");
268 PanicAlert("Install directory could not be saved");
271 fwrite(CWD
, ((std::string
)CWD
).size()+1, 1, workingDirF
);
272 fwrite("", 1, 1, workingDirF
); //seems to be needed on linux
277 PanicAlert("Relaunch Dolphin from the install directory and save from there");
284 fseek(workingDir
, 0, SEEK_END
);
285 len
= ftell(workingDir
);
286 fseek(workingDir
, 0, SEEK_SET
);
287 tmpChar
= new char[len
];
288 fread(tmpChar
, len
, 1, workingDir
);
290 if (!wxSetWorkingDirectory(wxString::From8BitData(tmpChar
)))
292 INFO_LOG(CONSOLE
, "set working directory failed");
300 const char *AppSupportDir
= File::GetUserPath(D_USER_IDX
);
302 if (!File::Exists(AppSupportDir
))
304 // Fresh run: create Dolphin dir and copy contents of User within the bundle to App Support
305 File::CopyDir(std::string(File::GetBundleDirectory() + DIR_SEP USERDATA_DIR DIR_SEP
).c_str(), AppSupportDir
);
307 else if (!File::IsDirectory(AppSupportDir
))
308 PanicAlert("~/Library/Application Support/Dolphin exists, but is not a directory");
312 //create all necessary directories in user directory
313 //TODO : detect the revision and upgrade where necessary
314 File::CopyDir(SHARED_USER_DIR CONFIG_DIR DIR_SEP
, File::GetUserPath(D_CONFIG_IDX
));
315 File::CopyDir(SHARED_USER_DIR GAMECONFIG_DIR DIR_SEP
, File::GetUserPath(D_GAMECONFIG_IDX
));
316 File::CopyDir(SHARED_USER_DIR MAPS_DIR DIR_SEP
, File::GetUserPath(D_MAPS_IDX
));
317 File::CopyDir(SHARED_USER_DIR SHADERS_DIR DIR_SEP
, File::GetUserPath(D_SHADERS_IDX
));
318 File::CopyDir(SHARED_USER_DIR WII_USER_DIR DIR_SEP
, File::GetUserPath(D_WIIUSER_IDX
));
320 if (!File::Exists(File::GetUserPath(D_GCUSER_IDX
)))
321 File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX
));
322 if (!File::Exists(File::GetUserPath(D_CACHE_IDX
)))
323 File::CreateFullPath(File::GetUserPath(D_CACHE_IDX
));
324 if (!File::Exists(File::GetUserPath(D_DUMPDSP_IDX
)))
325 File::CreateFullPath(File::GetUserPath(D_DUMPDSP_IDX
));
326 if (!File::Exists(File::GetUserPath(D_DUMPTEXTURES_IDX
)))
327 File::CreateFullPath(File::GetUserPath(D_DUMPTEXTURES_IDX
));
328 if (!File::Exists(File::GetUserPath(D_HIRESTEXTURES_IDX
)))
329 File::CreateFullPath(File::GetUserPath(D_HIRESTEXTURES_IDX
));
330 if (!File::Exists(File::GetUserPath(D_SCREENSHOTS_IDX
)))
331 File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX
));
332 if (!File::Exists(File::GetUserPath(D_STATESAVES_IDX
)))
333 File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX
));
334 if (!File::Exists(File::GetUserPath(D_MAILLOGS_IDX
)))
335 File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX
));
340 CPluginManager::Init();
342 if (selectVideoPlugin
&& videoPluginFilename
!= wxEmptyString
)
343 SConfig::GetInstance().m_LocalCoreStartupParameter
.m_strVideoPlugin
=
344 std::string(videoPluginFilename
.mb_str());
346 if (selectAudioPlugin
&& audioPluginFilename
!= wxEmptyString
)
347 SConfig::GetInstance().m_LocalCoreStartupParameter
.m_strDSPPlugin
=
348 std::string(audioPluginFilename
.mb_str());
350 if (selectWiimotePlugin
&& wiimotePluginFilename
!= wxEmptyString
)
351 SConfig::GetInstance().m_LocalCoreStartupParameter
.m_strWiimotePlugin
=
352 std::string(wiimotePluginFilename
.mb_str());
354 // Enable the PNG image handler
355 wxInitAllImageHandlers();
357 SetEnableAlert(SConfig::GetInstance().m_LocalCoreStartupParameter
.bUsePanicHandlers
);
359 int x
= SConfig::GetInstance().m_LocalCoreStartupParameter
.iPosX
;
360 int y
= SConfig::GetInstance().m_LocalCoreStartupParameter
.iPosY
;
361 int w
= SConfig::GetInstance().m_LocalCoreStartupParameter
.iWidth
;
362 int h
= SConfig::GetInstance().m_LocalCoreStartupParameter
.iHeight
;
364 // The following is not needed in linux. Linux window managers do not allow windows to
365 // be created off the desktop.
367 // Out of desktop check
368 HWND hDesktop
= GetDesktopWindow();
370 GetWindowRect(hDesktop
, &rc
);
371 if (rc
.right
< x
+ w
|| rc
.bottom
< y
+ h
)
375 main_frame
= new CFrame((wxFrame
*)NULL
, wxID_ANY
,
376 wxString::FromAscii(svn_rev_str
),
377 wxPoint(x
, y
), wxSize(w
, h
),
378 UseDebugger
, BatchMode
, UseLogger
);
379 SetTopWindow(main_frame
);
381 #if defined HAVE_X11 && HAVE_X11
385 // Postpone final actions until event handler is running
386 m_afterinit
= new wxTimer(this, wxID_ANY
);
387 m_afterinit
->Start(1, wxTIMER_ONE_SHOT
);
392 void DolphinApp::AfterInit(wxTimerEvent
& WXUNUSED(event
))
396 // Updating the game list makes use of wxProgressDialog which may
397 // only be run after OnInit() when the event handler is running.
398 main_frame
->UpdateGameList();
400 // Check the autoboot options:
402 // First check if we have an exec command line.
403 if (LoadFile
&& FileToLoad
!= wxEmptyString
)
405 main_frame
->BootGame(std::string(FileToLoad
.mb_str()));
408 // If we have selected Automatic Start, start the default ISO,
409 // or if no default ISO exists, start the last loaded ISO
410 else if (main_frame
->g_pCodeWindow
)
412 if (main_frame
->g_pCodeWindow
->AutomaticStart())
414 if(!SConfig::GetInstance().m_LocalCoreStartupParameter
.m_strDefaultGCM
.empty()
415 && File::Exists(SConfig::GetInstance().m_LocalCoreStartupParameter
.
416 m_strDefaultGCM
.c_str()))
418 main_frame
->BootGame(SConfig::GetInstance().m_LocalCoreStartupParameter
.
421 else if(!SConfig::GetInstance().m_LastFilename
.empty()
422 && File::Exists(SConfig::GetInstance().m_LastFilename
.c_str()))
424 main_frame
->BootGame(SConfig::GetInstance().m_LastFilename
);
430 void DolphinApp::OnEndSession()
432 SConfig::GetInstance().SaveSettings();
435 int DolphinApp::OnExit()
438 if (SConfig::GetInstance().m_WiiAutoUnpair
)
440 if (CPluginManager::GetInstance().GetWiimote())
441 CPluginManager::GetInstance().GetWiimote()->Wiimote_UnPairWiimotes();
444 CPluginManager::Shutdown();
446 LogManager::Shutdown();
448 return wxApp::OnExit();
456 // g_VideoInitialize.pSysMessage() goes here
457 void Host_SysMessage(const char *fmt
, ...)
463 vsprintf(msg
, fmt
, list
);
466 if (msg
[strlen(msg
)-1] == '\n') msg
[strlen(msg
)-1] = 0;
467 //wxMessageBox(wxString::FromAscii(msg));
468 PanicAlert("%s", msg
);
471 bool wxMsgAlert(const char* caption
, const char* text
, bool yes_no
, int /*Style*/)
473 return wxYES
== wxMessageBox(wxString::FromAscii(text
),
474 wxString::FromAscii(caption
),
475 (yes_no
)?wxYES_NO
:wxOK
);
478 // Accessor for the main window class
479 CFrame
* DolphinApp::GetCFrame()
484 void Host_Message(int Id
)
489 #if defined(HAVE_X11) && HAVE_X11
494 wxCommandEvent
event(wxEVT_HOST_COMMAND
, Id
);
495 main_frame
->GetEventHandler()->AddPendingEvent(event
);
499 main_frame
->OnCustomHostMessage(Id
);
503 // OK, this thread boundary is DANGEROUS on linux
504 // wxPostEvent / wxAddPendingEvent is the solution.
505 void Host_NotifyMapLoaded()
507 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_NOTIFYMAPLOADED
);
508 main_frame
->GetEventHandler()->AddPendingEvent(event
);
510 if (main_frame
->g_pCodeWindow
)
512 main_frame
->g_pCodeWindow
->GetEventHandler()->AddPendingEvent(event
);
517 void Host_UpdateLogDisplay()
519 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_UPDATELOGDISPLAY
);
520 main_frame
->GetEventHandler()->AddPendingEvent(event
);
522 if (main_frame
->g_pCodeWindow
)
524 main_frame
->g_pCodeWindow
->GetEventHandler()->AddPendingEvent(event
);
529 void Host_UpdateDisasmDialog()
531 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_UPDATEDISASMDIALOG
);
532 main_frame
->GetEventHandler()->AddPendingEvent(event
);
534 if (main_frame
->g_pCodeWindow
)
536 main_frame
->g_pCodeWindow
->GetEventHandler()->AddPendingEvent(event
);
541 void Host_ShowJitResults(unsigned int address
)
543 CJitWindow::ViewAddr(address
);
546 void Host_UpdateMainFrame()
548 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_UPDATEGUI
);
549 main_frame
->GetEventHandler()->AddPendingEvent(event
);
551 if (main_frame
->g_pCodeWindow
)
553 main_frame
->g_pCodeWindow
->GetEventHandler()->AddPendingEvent(event
);
557 void Host_UpdateTitle(const char* title
)
559 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_UPDATETITLE
);
560 event
.SetString(wxString::FromAscii(title
));
561 main_frame
->GetEventHandler()->AddPendingEvent(event
);
564 void Host_UpdateBreakPointView()
566 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_UPDATEBREAKPOINTS
);
567 main_frame
->GetEventHandler()->AddPendingEvent(event
);
569 if (main_frame
->g_pCodeWindow
)
571 main_frame
->g_pCodeWindow
->GetEventHandler()->AddPendingEvent(event
);
575 void Host_UpdateMemoryView()
578 void Host_SetDebugMode(bool)
581 void Host_RequestWindowSize(int& x
, int& y
, int& width
, int& height
)
583 main_frame
->OnSizeRequest(x
, y
, width
, height
);
586 void Host_SetWaitCursor(bool enable
)
594 void Host_UpdateStatusBar(const char* _pText
, int Field
)
596 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_UPDATESTATUSBAR
);
597 // Set the event string
598 event
.SetString(wxString::FromAscii(_pText
));
599 // Update statusbar field
602 // TODO : this has been said to cause hang (??) how is that even possible ? :d
603 event
.StopPropagation();
604 main_frame
->GetEventHandler()->AddPendingEvent(event
);
607 void Host_SetWiiMoteConnectionState(int _State
)
609 static int currentState
= -1;
610 if (_State
== currentState
)
612 currentState
= _State
;
614 wxCommandEvent
event(wxEVT_HOST_COMMAND
, IDM_UPDATESTATUSBAR
);
618 case 0: event
.SetString(wxString::FromAscii("Not connected")); break;
619 case 1: event
.SetString(wxString::FromAscii("Connecting...")); break;
620 case 2: event
.SetString(wxString::FromAscii("Wiimote Connected")); break;
622 // Update field 1 or 2
625 main_frame
->GetEventHandler()->AddPendingEvent(event
);
628 bool Host_RendererHasFocus()
630 return main_frame
->RendererHasFocus();