/[pcsx2_0.9.7]/trunk/pcsx2/gui/AppInit.cpp
ViewVC logotype

Contents of /trunk/pcsx2/gui/AppInit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 290 - (show annotations) (download)
Sat Dec 25 02:51:30 2010 UTC (9 years ago) by william
File size: 29174 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4139 local: v0.9.7.283-latest) in ./trunk
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "MainFrame.h"
18 #include "AppAccelerators.h"
19 #include "ConsoleLogger.h"
20 #include "MSWstuff.h"
21
22 #include "Utilities/IniInterface.h"
23 #include "Utilities/HashMap.h"
24 #include "DebugTools/Debug.h"
25 #include "Dialogs/ModalPopups.h"
26
27 #include <wx/cmdline.h>
28 #include <wx/intl.h>
29 #include <wx/stdpaths.h>
30
31 using namespace pxSizerFlags;
32
33 static void CpuCheckSSE2()
34 {
35 if( x86caps.hasStreamingSIMD2Extensions ) return;
36
37 // Only check once per process session:
38 static bool checked = false;
39 if( checked ) return;
40 checked = true;
41
42 wxDialogWithHelpers exconf( NULL, _("PCSX2 - SSE2 Recommended") );
43
44 exconf += exconf.Heading( pxE( "!Notice:Startup:NoSSE2",
45 L"Warning: Your computer does not support SSE2, which is required by many PCSX2 recompilers and plugins. "
46 L"Your options will be limited and emulation will be *very* slow." )
47 );
48
49 pxIssueConfirmation( exconf, MsgButtons().OK(), L"Error.Startup.NoSSE2" );
50
51 // Auto-disable anything that needs SSE2:
52
53 g_Conf->EmuOptions.Cpu.Recompiler.EnableEE = false;
54 g_Conf->EmuOptions.Cpu.Recompiler.EnableVU0 = false;
55 g_Conf->EmuOptions.Cpu.Recompiler.EnableVU1 = false;
56 }
57
58 void Pcsx2App::WipeUserModeSettings()
59 {
60 wxDirName usrlocaldir = PathDefs::GetUserLocalDataDir();
61 if( !usrlocaldir.Exists() ) return;
62
63 wxString cwd( Path::Normalize( wxGetCwd() ) );
64 #ifdef __WXMSW__
65 cwd.MakeLower();
66 #endif
67 u32 hashres = HashTools::Hash( (char*)cwd.c_str(), cwd.Length()*sizeof(wxChar) );
68
69 wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() );
70 usermodefile.SetPath( usrlocaldir.ToString() );
71 ScopedPtr<wxFileConfig> conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) );
72
73 FastFormatUnicode groupname;
74 groupname.Write( L"CWD.%08x", hashres );
75 Console.WriteLn( "(UserModeSettings) Removing entry:" );
76 Console.Indent().WriteLn( L"Path: %s\nHash:%s", cwd.c_str(), groupname.c_str() );
77 conf_usermode->DeleteGroup( groupname );
78 }
79
80 static void DoFirstTimeWizard()
81 {
82 // first time startup, so give the user the choice of user mode:
83 while(true)
84 {
85 // PCSX2's FTWizard allows improptu restarting of the wizard without cancellation. This is
86 // typically used to change the user's language selection.
87
88 FirstTimeWizard wiz( NULL );
89 if( wiz.RunWizard( wiz.GetUsermodePage() ) ) break;
90 if (wiz.GetReturnCode() != pxID_RestartWizard)
91 throw Exception::StartupAborted( L"User canceled FirstTime Wizard." );
92
93 Console.WriteLn( Color_StrongBlack, "Restarting First Time Wizard!" );
94 }
95 }
96
97 // User mode settings can't be stored in the CWD for two reasons:
98 // (a) the user may not have permission to do so (most obvious)
99 // (b) it would result in sloppy usermode.ini found all over a hard drive if people runs the
100 // exe from many locations (ugh).
101 //
102 // So better to use the registry on Win32 and a "default ini location" config file under Linux,
103 // and store the usermode settings for the CWD based on the CWD's hash.
104 //
105 void Pcsx2App::ReadUserModeSettings()
106 {
107 wxDirName usrlocaldir = PathDefs::GetUserLocalDataDir();
108 if( !usrlocaldir.Exists() )
109 {
110 Console.WriteLn( L"Creating UserLocalData folder: " + usrlocaldir.ToString() );
111 usrlocaldir.Mkdir();
112 }
113
114 wxString cwd( Path::Normalize( wxGetCwd() ) );
115 #ifdef __WXMSW__
116 cwd.MakeLower();
117 #endif
118
119 u32 hashres = HashTools::Hash( (char*)cwd.c_str(), cwd.Length()*sizeof(wxChar) );
120
121 wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() );
122 usermodefile.SetPath( usrlocaldir.ToString() );
123 ScopedPtr<wxFileConfig> conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) );
124
125 FastFormatUnicode groupname;
126 groupname.Write( L"CWD.%08x", hashres );
127
128 bool hasGroup = conf_usermode->HasGroup( groupname );
129 bool forceWiz = Startup.ForceWizard || !hasGroup;
130
131 if( !forceWiz )
132 {
133 conf_usermode->SetPath( groupname );
134 forceWiz = !conf_usermode->HasEntry( L"DocumentsFolderMode" );
135 conf_usermode->SetPath( L".." );
136 }
137
138 if( forceWiz )
139 {
140 // Beta Warning!
141 #if 0
142 if( !hasGroup )
143 {
144 wxDialogWithHelpers beta( NULL, _fmt("Welcome to %s (%s)", pxGetAppName().c_str(), wxPCSX2_FULL_VERSION() ));
145 beta.SetMinWidth(480);
146
147 beta += beta.Heading(
148 L"PCSX2 0.9.7 is a work-in-progress. We are in the middle of major rewrites of the user interface, and some parts "
149 L"of the program have *NOT* been re-implemented yet. Options will be missing or disabled. Horrible crashes might be present. Enjoy!"
150 );
151 beta += StdPadding*2;
152 beta += new wxButton( &beta, wxID_OK ) | StdCenter();
153 beta.ShowModal();
154 }
155 #endif
156
157 DoFirstTimeWizard();
158
159 // Save user's new settings
160 IniSaver saver( *conf_usermode );
161 g_Conf->LoadSaveUserMode( saver, groupname );
162 AppConfig_OnChangedSettingsFolder( true );
163 AppSaveSettings();
164 }
165 else
166 {
167 // usermode.ini exists and is populated with valid data -- assume User Documents mode,
168 // unless the ini explicitly specifies otherwise.
169
170 DocsFolderMode = DocsFolder_User;
171
172 IniLoader loader( *conf_usermode );
173 g_Conf->LoadSaveUserMode( loader, groupname );
174
175 if( !wxFile::Exists( GetSettingsFilename() ) )
176 {
177 // user wiped their pcsx2.ini -- needs a reconfiguration via wizard!
178
179 DoFirstTimeWizard();
180
181 // Save user's new settings
182 IniSaver saver( *conf_usermode );
183 g_Conf->LoadSaveUserMode( saver, groupname );
184 AppConfig_OnChangedSettingsFolder( true );
185 AppSaveSettings();
186 }
187 }
188
189 // force unload plugins loaded by the wizard. If we don't do this the recompilers might
190 // fail to allocate the memory they need to function.
191 UnloadPlugins();
192 }
193
194 void Pcsx2App::DetectCpuAndUserMode()
195 {
196 AffinityAssert_AllowFrom_MainUI();
197
198 x86caps.Identify();
199 x86caps.CountCores();
200 x86caps.SIMD_EstablishMXCSRmask();
201
202 if( !x86caps.hasMultimediaExtensions || !x86caps.hasStreamingSIMDExtensions )
203 {
204 // Note: Due to optimizations to GIFpath parsers, memcpy, and possibly other things, we need
205 // a bare minimum of SSE supported by the CPU.
206 throw Exception::HardwareDeficiency()
207 .SetDiagMsg(L"Critical Failure: SSE Extensions not available.")
208 .SetUserMsg(_("SSE extensions are not available. PCSX2 requires a cpu that supports the SSE instruction set."));
209 }
210
211 ReadUserModeSettings();
212 AppConfig_OnChangedSettingsFolder();
213 }
214
215 void Pcsx2App::OpenMainFrame()
216 {
217 if( AppRpc_TryInvokeAsync( &Pcsx2App::OpenMainFrame ) ) return;
218
219 if( GetMainFramePtr() != NULL ) return;
220
221 MainEmuFrame* mainFrame = new MainEmuFrame( NULL, pxGetAppName() );
222 m_id_MainFrame = mainFrame->GetId();
223
224 PostIdleAppMethod( &Pcsx2App::OpenProgramLog );
225
226 SetTopWindow( mainFrame ); // not really needed...
227 SetExitOnFrameDelete( false ); // but being explicit doesn't hurt...
228 mainFrame->Show();
229 }
230
231 void Pcsx2App::OpenProgramLog()
232 {
233 if( AppRpc_TryInvokeAsync( &Pcsx2App::OpenProgramLog ) ) return;
234
235 if( ConsoleLogFrame* frame = GetProgramLog() )
236 {
237 //pxAssume( );
238 return;
239 }
240
241 wxWindow* m_current_focus = wxGetActiveWindow();
242
243 ScopedLock lock( m_mtx_ProgramLog );
244 m_ptr_ProgramLog = new ConsoleLogFrame( GetMainFramePtr(), L"PCSX2 Program Log", g_Conf->ProgLogBox );
245 m_id_ProgramLogBox = m_ptr_ProgramLog->GetId();
246 EnableAllLogging();
247
248 if( m_current_focus ) m_current_focus->SetFocus();
249
250 // This is test code for printing out all supported languages and their canonical names in wiki-fied
251 // format. I might use it again soon, so I'm leaving it in for now... --air
252 /*
253 for( int li=wxLANGUAGE_UNKNOWN+1; li<wxLANGUAGE_USER_DEFINED; ++li )
254 {
255 if (const wxLanguageInfo* info = wxLocale::GetLanguageInfo( li ))
256 {
257 if (i18n_IsLegacyLanguageId((wxLanguage)info->Language)) continue;
258 Console.WriteLn( L"|| %-30s || %-8s ||", info->Description.c_str(), info->CanonicalName.c_str() );
259 }
260 }
261 */
262 }
263
264 void Pcsx2App::AllocateCoreStuffs()
265 {
266 if( AppRpc_TryInvokeAsync( &Pcsx2App::AllocateCoreStuffs ) ) return;
267
268 CpuCheckSSE2();
269 SysLogMachineCaps();
270 AppApplySettings();
271
272 GetVmReserve().ReserveAll();
273
274 if( !m_CpuProviders )
275 {
276 // FIXME : Some or all of SysCpuProviderPack should be run from the SysExecutor thread,
277 // so that the thread is safely blocked from being able to start emulation.
278
279 m_CpuProviders = new SysCpuProviderPack();
280
281 if( m_CpuProviders->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
282 {
283 // HadSomeFailures only returns 'true' if an *enabled* cpu type fails to init. If
284 // the user already has all interps configured, for example, then no point in
285 // popping up this dialog.
286
287 wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)") );
288
289 exconf += 12;
290 exconf += exconf.Heading( pxE( "!Notice:RecompilerInit:Header",
291 L"Warning: Some of the configured PS2 recompilers failed to initialize and have been disabled:" )
292 );
293
294 wxTextCtrl* scrollableTextArea = new wxTextCtrl(
295 &exconf, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
296 wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP
297 );
298
299 exconf += 6;
300 exconf += scrollableTextArea | pxExpand.Border(wxALL, 16);
301
302 Pcsx2Config::RecompilerOptions& recOps = g_Conf->EmuOptions.Cpu.Recompiler;
303
304 if( BaseException* ex = m_CpuProviders->GetException_EE() )
305 {
306 scrollableTextArea->AppendText( L"* R5900 (EE)\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
307 recOps.EnableEE = false;
308 }
309
310 if( BaseException* ex = m_CpuProviders->GetException_IOP() )
311 {
312 scrollableTextArea->AppendText( L"* R3000A (IOP)\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
313 recOps.EnableIOP = false;
314 }
315
316 if( BaseException* ex = m_CpuProviders->GetException_MicroVU0() )
317 {
318 scrollableTextArea->AppendText( L"* microVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
319 recOps.UseMicroVU0 = false;
320 recOps.EnableVU0 = recOps.EnableVU0 && m_CpuProviders->IsRecAvailable_SuperVU0();
321 }
322
323 if( BaseException* ex = m_CpuProviders->GetException_MicroVU1() )
324 {
325 scrollableTextArea->AppendText( L"* microVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
326 recOps.UseMicroVU1 = false;
327 recOps.EnableVU1 = recOps.EnableVU1 && m_CpuProviders->IsRecAvailable_SuperVU1();
328 }
329
330 if( BaseException* ex = m_CpuProviders->GetException_SuperVU0() )
331 {
332 scrollableTextArea->AppendText( L"* SuperVU0\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
333 recOps.UseMicroVU0 = m_CpuProviders->IsRecAvailable_MicroVU0();
334 recOps.EnableVU0 = recOps.EnableVU0 && recOps.UseMicroVU0;
335 }
336
337 if( BaseException* ex = m_CpuProviders->GetException_SuperVU1() )
338 {
339 scrollableTextArea->AppendText( L"* SuperVU1\n\t" + ex->FormatDisplayMessage() + L"\n\n" );
340 recOps.UseMicroVU1 = m_CpuProviders->IsRecAvailable_MicroVU1();
341 recOps.EnableVU1 = recOps.EnableVU1 && recOps.UseMicroVU1;
342 }
343
344 exconf += exconf.Heading( pxE("!Notice:RecompilerInit:Footer",
345 L"Note: Recompilers are not necessary for PCSX2 to run, however they typically improve emulation speed substantially. "
346 L"You may have to manually re-enable the recompilers listed above, if you resolve the errors." )
347 );
348
349 pxIssueConfirmation( exconf, MsgButtons().OK() );
350 }
351 }
352
353 LoadPluginsPassive();
354 }
355
356
357 void Pcsx2App::OnInitCmdLine( wxCmdLineParser& parser )
358 {
359 parser.SetLogo( AddAppName(" >> %s -- A Playstation2 Emulator for the PC <<") + L"\n\n" +
360 _("All options are for the current session only and will not be saved.\n")
361 );
362
363 wxString fixlist( L" " );
364 for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i)
365 {
366 if( i != GamefixId_FIRST ) fixlist += L",";
367 fixlist += EnumToString(i);
368 }
369
370 parser.AddParam( _("IsoFile"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL );
371 parser.AddSwitch( L"h", L"help", _("displays this list of command line options"), wxCMD_LINE_OPTION_HELP );
372 parser.AddSwitch( wxEmptyString,L"console", _("forces the program log/console to be visible"), wxCMD_LINE_VAL_STRING );
373 parser.AddSwitch( wxEmptyString,L"fullscreen", _("use fullscreen GS mode") );
374 parser.AddSwitch( wxEmptyString,L"windowed", _("use windowed GS mode") );
375
376 parser.AddSwitch( wxEmptyString,L"nogui", _("disables display of the gui while running games") );
377 parser.AddOption( wxEmptyString,L"elf", _("executes an ELF image"), wxCMD_LINE_VAL_STRING );
378 parser.AddSwitch( wxEmptyString,L"nodisc", _("boots an empty dvd tray; use to enter the PS2 system menu") );
379 parser.AddSwitch( wxEmptyString,L"usecd", _("boots from the CDVD plugin (overrides IsoFile parameter)") );
380
381 parser.AddSwitch( wxEmptyString,L"nohacks", _("disables all speedhacks") );
382 parser.AddOption( wxEmptyString,L"gamefixes", _("use the specified comma or pipe-delimited list of gamefixes.") + fixlist, wxCMD_LINE_VAL_STRING );
383 parser.AddSwitch( wxEmptyString,L"fullboot", _("disables fast booting") );
384
385 parser.AddOption( wxEmptyString,L"cfgpath", _("changes the configuration file path"), wxCMD_LINE_VAL_STRING );
386 parser.AddOption( wxEmptyString,L"cfg", _("specifies the PCSX2 configuration file to use"), wxCMD_LINE_VAL_STRING );
387 parser.AddSwitch( wxEmptyString,L"forcewiz", AddAppName(_("forces %s to start the First-time Wizard")) );
388
389 const PluginInfo* pi = tbl_PluginInfo; do {
390 parser.AddOption( wxEmptyString, pi->GetShortname().Lower(),
391 pxsFmt( _("specify the file to use as the %s plugin"), pi->GetShortname().c_str() )
392 );
393 } while( ++pi, pi->shortname != NULL );
394
395 parser.SetSwitchChars( L"-" );
396 }
397
398 bool Pcsx2App::OnCmdLineError( wxCmdLineParser& parser )
399 {
400 wxApp::OnCmdLineError( parser );
401 return false;
402 }
403
404 bool Pcsx2App::ParseOverrides( wxCmdLineParser& parser )
405 {
406 wxString dest;
407
408 if (parser.Found( L"cfgpath", &dest ) && !dest.IsEmpty())
409 {
410 Console.Warning( L"Config path override: " + dest );
411 Overrides.SettingsFolder = dest;
412 }
413
414 if (parser.Found( L"cfg", &dest ) && !dest.IsEmpty())
415 {
416 Console.Warning( L"Config file override: " + dest );
417 Overrides.SettingsFile = dest;
418 }
419
420 Overrides.DisableSpeedhacks = parser.Found(L"nohacks");
421
422 if (parser.Found(L"gamefixes", &dest))
423 {
424 Overrides.ApplyCustomGamefixes = true;
425 Overrides.Gamefixes.Set( dest, true );
426 }
427
428 if (parser.Found(L"fullscreen")) Overrides.GsWindowMode = GsWinMode_Fullscreen;
429 if (parser.Found(L"windowed")) Overrides.GsWindowMode = GsWinMode_Windowed;
430
431 const PluginInfo* pi = tbl_PluginInfo; do
432 {
433 if( !parser.Found( pi->GetShortname().Lower(), &dest ) ) continue;
434
435 if( wxFileExists( dest ) )
436 Console.Warning( pi->GetShortname() + L" override: " + dest );
437 else
438 {
439 wxDialogWithHelpers okcan( NULL, AddAppName(_("Plugin Override Error - %s")) );
440
441 okcan += okcan.Heading( wxsFormat(
442 _("%s Plugin Override Error! The following file does not exist or is not a valid %s plugin:\n\n"),
443 pi->GetShortname().c_str(), pi->GetShortname().c_str()
444 ) );
445
446 okcan += okcan.GetCharHeight();
447 okcan += okcan.Text(dest);
448 okcan += okcan.GetCharHeight();
449 okcan += okcan.Heading(AddAppName(_("Press OK to use the default configured plugin, or Cancel to close %s.")));
450
451 if( wxID_CANCEL == pxIssueConfirmation( okcan, MsgButtons().OKCancel() ) ) return false;
452 }
453
454 Overrides.Filenames.Plugins[pi->id] = dest;
455
456 } while( ++pi, pi->shortname != NULL );
457
458 return true;
459 }
460
461 bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser )
462 {
463 if( parser.Found(L"console") )
464 {
465 Startup.ForceConsole = true;
466 OpenProgramLog();
467 }
468
469 // Suppress wxWidgets automatic options parsing since none of them pertain to PCSX2 needs.
470 //wxApp::OnCmdLineParsed( parser );
471
472 m_UseGUI = !parser.Found(L"nogui");
473
474 if( !ParseOverrides(parser) ) return false;
475
476 // --- Parse Startup/Autoboot options ---
477
478 Startup.NoFastBoot = parser.Found(L"fullboot");
479 Startup.ForceWizard = parser.Found(L"forcewiz");
480
481 if( parser.GetParamCount() >= 1 )
482 {
483 Startup.IsoFile = parser.GetParam( 0 );
484 Startup.SysAutoRun = true;
485 }
486
487 if( parser.Found(L"usecd") )
488 {
489 Startup.CdvdSource = CDVDsrc_Plugin;
490 Startup.SysAutoRun = true;
491 }
492
493 return true;
494 }
495
496 typedef void (wxEvtHandler::*pxInvokeAppMethodEventFunction)(Pcsx2AppMethodEvent&);
497 typedef void (wxEvtHandler::*pxStuckThreadEventHandler)(pxMessageBoxEvent&);
498
499 // --------------------------------------------------------------------------------------
500 // GameDatabaseLoaderThread
501 // --------------------------------------------------------------------------------------
502 class GameDatabaseLoaderThread : public pxThread
503 , EventListener_AppStatus
504 {
505 typedef pxThread _parent;
506
507 public:
508 GameDatabaseLoaderThread()
509 : pxThread( L"GameDatabaseLoader" )
510 {
511 }
512
513 virtual ~GameDatabaseLoaderThread() throw()
514 {
515 _parent::Cancel();
516 }
517
518 protected:
519 void ExecuteTaskInThread()
520 {
521 Sleep(2);
522 wxGetApp().GetGameDatabase();
523 }
524
525 void OnCleanupInThread()
526 {
527 _parent::OnCleanupInThread();
528 wxGetApp().DeleteThread(this);
529 }
530
531 void AppStatusEvent_OnExit()
532 {
533 Block();
534 }
535 };
536
537 bool Pcsx2App::OnInit()
538 {
539 EnableAllLogging();
540 Console.WriteLn("Interface is initializing. Entering Pcsx2App::OnInit!");
541
542 InitCPUTicks();
543
544 pxDoAssert = AppDoAssert;
545 pxDoOutOfMemory = SysOutOfMemory_EmergencyResponse;
546
547 g_Conf = new AppConfig();
548 wxInitAllImageHandlers();
549
550 Console.WriteLn("Applying operating system default language...");
551 i18n_SetLanguage( wxLANGUAGE_DEFAULT );
552
553 Console.WriteLn("Command line parsing...");
554 if( !_parent::OnInit() ) return false;
555 Console.WriteLn("Command line parsed!");
556
557 wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
558
559 #define pxAppMethodEventHandler(func) \
560 (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxInvokeAppMethodEventFunction, &func )
561
562 Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler (Pcsx2App::OnEmuKeyDown) );
563 Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler (Pcsx2App::OnDestroyWindow) );
564
565 // User/Admin Mode Dual Setup:
566 // PCSX2 now supports two fundamental modes of operation. The default is Classic mode,
567 // which uses the Current Working Directory (CWD) for all user data files, and requires
568 // Admin access on Vista (and some Linux as well). The second mode is the Vista-
569 // compatible \documents folder usage. The mode is determined by the presence and
570 // contents of a usermode.ini file in the CWD. If the ini file is missing, we assume
571 // the user is setting up a classic install. If the ini is present, we read the value of
572 // the UserMode and SettingsPath vars.
573 //
574 // Conveniently this dual mode setup applies equally well to most modern Linux distros.
575
576 try
577 {
578 InitDefaultGlobalAccelerators();
579 delete wxLog::SetActiveTarget( new pxLogConsole() );
580
581 #ifdef __WXMSW__
582 pxDwm_Load();
583 #endif
584 SysExecutorThread.Start();
585 DetectCpuAndUserMode();
586
587 // Set Manual Exit Handling
588 // ----------------------------
589 // PCSX2 has a lot of event handling logistics, so we *cannot* depend on wxWidgets automatic event
590 // loop termination code. We have a much safer system in place that continues to process messages
591 // until all "important" threads are closed out -- not just until the main frame is closed(-ish).
592 m_timer_Termination = new wxTimer( this, wxID_ANY );
593 Connect( m_timer_Termination->GetId(), wxEVT_TIMER, wxTimerEventHandler(Pcsx2App::OnScheduledTermination) );
594 SetExitOnFrameDelete( false );
595
596
597 // Start GUI and/or Direct Emulation
598 // -------------------------------------
599 if( Startup.ForceConsole ) g_Conf->ProgLogBox.Visible = true;
600 OpenProgramLog();
601 AllocateCoreStuffs();
602 if( m_UseGUI ) OpenMainFrame();
603
604 (new GameDatabaseLoaderThread())->Start();
605
606 if( Startup.SysAutoRun )
607 {
608 // Notes: Saving/remembering the Iso file is probably fine and desired, so using
609 // SysUpdateIsoSrcFile is good(ish).
610 // Saving the cdvd plugin override isn't desirable, so we don't assign it into g_Conf.
611
612 g_Conf->EmuOptions.UseBOOT2Injection = !Startup.NoFastBoot;
613 SysUpdateIsoSrcFile( Startup.IsoFile );
614 sApp.SysExecute( Startup.CdvdSource );
615 }
616 }
617 // ----------------------------------------------------------------------------
618 catch( Exception::StartupAborted& ex ) // user-aborted, no popups needed.
619 {
620 Console.Warning( ex.FormatDiagnosticMessage() );
621 CleanupOnExit();
622 return false;
623 }
624 catch( Exception::HardwareDeficiency& ex )
625 {
626 Msgbox::Alert( ex.FormatDisplayMessage() + AddAppName(_("\n\nPress OK to close %s.")), _("PCSX2 Error: Hardware Deficiency") );
627 CleanupOnExit();
628 return false;
629 }
630 // ----------------------------------------------------------------------------
631 // Failures on the core initialization procedure (typically OutOfMemory errors) are bad,
632 // since it means the emulator is completely non-functional. Let's pop up an error and
633 // exit gracefully-ish.
634 //
635 catch( Exception::RuntimeError& ex )
636 {
637 Console.Error( ex.FormatDiagnosticMessage() );
638 Msgbox::Alert( ex.FormatDisplayMessage() + AddAppName(_("\n\nPress OK to close %s.")),
639 AddAppName(_("%s Critical Error")), wxICON_ERROR );
640 CleanupOnExit();
641 return false;
642 }
643 return true;
644 }
645
646 static int m_term_threshold = 20;
647
648 void Pcsx2App::OnScheduledTermination( wxTimerEvent& evt )
649 {
650 if( !pxAssertDev( m_ScheduledTermination, "Scheduled Termination check is inconsistent with ScheduledTermination status." ) )
651 {
652 m_timer_Termination->Stop();
653 return;
654 }
655
656 if( m_PendingSaves != 0 )
657 {
658 if( --m_term_threshold > 0 )
659 {
660 Console.WriteLn( "(App) %d saves are still pending; exit postponed...", m_PendingSaves );
661 return;
662 }
663
664 Console.Error( "(App) %s pending saves have exceeded OnExit threshold and are being prematurely terminated!", m_PendingSaves );
665 }
666
667 m_timer_Termination->Stop();
668 Exit();
669 }
670
671
672 // Common exit handler which can be called from any event (though really it should
673 // be called only from CloseWindow handlers since that's the more appropriate way
674 // to handle cancelable window closures)
675 //
676 // returns true if the app can close, or false if the close event was canceled by
677 // the glorious user, whomever (s)he-it might be.
678 void Pcsx2App::PrepForExit()
679 {
680 if( m_ScheduledTermination ) return;
681 m_ScheduledTermination = true;
682
683 DispatchEvent( AppStatus_Exiting );
684
685 CoreThread.Cancel();
686 SysExecutorThread.ShutdownQueue();
687
688 m_timer_Termination->Start( 500 );
689 }
690
691 // This cleanup procedure can only be called when the App message pump is still active.
692 // OnExit() must use CleanupOnExit instead.
693 void Pcsx2App::CleanupRestartable()
694 {
695 AffinityAssert_AllowFrom_MainUI();
696
697 CoreThread.Cancel();
698 SysExecutorThread.ShutdownQueue();
699 IdleEventDispatcher( L"Cleanup" );
700
701 if( g_Conf ) AppSaveSettings();
702 }
703
704 // This cleanup handler can be called from OnExit (it doesn't need a running message pump),
705 // but should not be called from the App destructor. It's needed because wxWidgets doesn't
706 // always call OnExit(), so I had to make CleanupRestartable, and then encapsulate it here
707 // to be friendly to the OnExit scenario (no message pump).
708 void Pcsx2App::CleanupOnExit()
709 {
710 AffinityAssert_AllowFrom_MainUI();
711
712 try
713 {
714 CleanupRestartable();
715 CleanupResources();
716 }
717 catch( Exception::CancelEvent& ) { throw; }
718 catch( Exception::RuntimeError& ex )
719 {
720 // Handle runtime errors gracefully during shutdown. Mostly these are things
721 // that we just don't care about by now, and just want to "get 'er done!" so
722 // we can exit the app. ;)
723
724 Console.Error( L"Runtime exception handled during CleanupOnExit:\n" );
725 Console.Indent().Error( ex.FormatDiagnosticMessage() );
726 }
727
728 #ifdef __WXMSW__
729 pxDwm_Unload();
730 #endif
731
732 // Notice: deleting the plugin manager (unloading plugins) here causes Lilypad to crash,
733 // likely due to some pending message in the queue that references lilypad procs.
734 // We don't need to unload plugins anyway tho -- shutdown is plenty safe enough for
735 // closing out all the windows. So just leave it be and let the plugins get unloaded
736 // during the wxApp destructor. -- air
737
738 // FIXME: performing a wxYield() here may fix that problem. -- air
739
740 pxDoAssert = pxAssertImpl_LogIt;
741 Console_SetActiveHandler( ConsoleWriter_Stdout );
742 }
743
744 void Pcsx2App::CleanupResources()
745 {
746 ScopedBusyCursor cursor( Cursor_ReallyBusy );
747 delete wxConfigBase::Set( NULL );
748
749 while( wxGetLocale() != NULL )
750 delete wxGetLocale();
751
752 m_mtx_LoadingGameDB.Wait();
753 ScopedLock lock(m_mtx_Resources);
754 m_Resources = NULL;
755 }
756
757 int Pcsx2App::OnExit()
758 {
759 CleanupOnExit();
760 return wxApp::OnExit();
761 }
762
763 void Pcsx2App::OnDestroyWindow( wxWindowDestroyEvent& evt )
764 {
765 // Precautions:
766 // * Whenever windows are destroyed, make sure to check if it matches our "active"
767 // console logger. If so, we need to disable logging to the console window, or else
768 // it'll crash. (this is because the console log system uses a cached window handle
769 // instead of looking the window up via it's ID -- fast but potentially unsafe).
770 //
771 // * The virtual machine's plugins usually depend on the GS window handle being valid,
772 // so if the GS window is the one being shut down then we need to make sure to close
773 // out the Corethread before it vanishes completely from existence.
774
775
776 OnProgramLogClosed( evt.GetId() );
777 OnGsFrameClosed( evt.GetId() );
778 evt.Skip();
779 }
780
781 // --------------------------------------------------------------------------------------
782 // SysEventHandler
783 // --------------------------------------------------------------------------------------
784 class SysEvtHandler : public pxEvtHandler
785 {
786 public:
787 wxString GetEvtHandlerName() const { return L"SysExecutor"; }
788
789 protected:
790 // When the SysExec message queue is finally empty, we should check the state of
791 // the menus and make sure they're all consistent to the current emulation states.
792 void _DoIdle()
793 {
794 UI_UpdateSysControls();
795 }
796 };
797
798
799 Pcsx2App::Pcsx2App()
800 : SysExecutorThread( new SysEvtHandler() )
801 {
802 #if 0
803 {
804 // Some common labels provided by wxWidgets. wxWidgets translation files are chucked full
805 // of worthless crap, and tally more than 200k each. We only need these couple.
806
807 _("OK");
808 _("&OK");
809 _("Cancel");
810 _("&Cancel");
811 _("&Apply");
812 _("&Next >");
813 _("&Back >");
814 _("&Back");
815 _("&Finish");
816
817 _("&Save");
818 _("Save &As...");
819 _("&Help");
820 _("&Home");
821 }
822 #endif
823
824 m_PendingSaves = 0;
825 m_ScheduledTermination = false;
826
827 m_id_MainFrame = wxID_ANY;
828 m_id_GsFrame = wxID_ANY;
829 m_id_ProgramLogBox = wxID_ANY;
830 m_ptr_ProgramLog = NULL;
831
832 SetAppName( L"PCSX2" );
833 BuildCommandHash();
834 }
835
836 Pcsx2App::~Pcsx2App()
837 {
838 pxDoAssert = pxAssertImpl_LogIt;
839 }
840
841 void Pcsx2App::CleanUp()
842 {
843 CleanupResources();
844 m_Resources = NULL;
845 m_RecentIsoList = NULL;
846
847 DisableDiskLogging();
848
849 if( emuLog != NULL )
850 {
851 fclose( emuLog );
852 emuLog = NULL;
853 }
854
855 _parent::CleanUp();
856 }
857
858 __fi wxString AddAppName( const wxChar* fmt )
859 {
860 return pxsFmt( fmt, pxGetAppName().c_str() );
861 }
862
863 __fi wxString AddAppName( const char* fmt )
864 {
865 return pxsFmt( fromUTF8(fmt), pxGetAppName().c_str() );
866 }
867
868 // ------------------------------------------------------------------------------------------
869 // Using the MSVCRT to track memory leaks:
870 // ------------------------------------------------------------------------------------------
871 // When exiting PCSX2 normally, the CRT will make a list of all memory that's leaked. The
872 // number inside {} can be pasted into the line below to cause MSVC to breakpoint on that
873 // allocation at the time it's made. And then using a stacktrace you can figure out what
874 // leaked! :D
875 //
876 // Limitations: Unfortunately, wxWidgets gui uses a lot of heap allocations while handling
877 // messages, and so any mouse movements will pretty much screw up the leak value. So to use
878 // this feature you need to execute pcsx in no-gui mode, and then not move the mouse or use
879 // the keyboard until you get to the leak. >_<
880 //
881 // (but this tool is still better than nothing!)
882
883 #ifdef PCSX2_DEBUG
884 struct CrtDebugBreak
885 {
886 CrtDebugBreak( int spot )
887 {
888 #ifdef __WXMSW__
889 _CrtSetBreakAlloc( spot );
890 #endif
891 }
892 };
893
894 //CrtDebugBreak breakAt( 11549 );
895
896 #endif

  ViewVC Help
Powered by ViewVC 1.1.22