/[pcsx2_0.9.7]/branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/AppInit.cpp
ViewVC logotype

Contents of /branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/AppInit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22