From 2300f972e45ee2f099bc2f35a930581bfc4be8cf Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Tue, 15 Jun 2010 14:13:23 +0000 Subject: [PATCH] Commandline, UI, and Game Database Work: * Improved console window behavior during startup and shutdown (also fixes minor threading issues) * Added better failsafes for avoiding "rouge" pcsx2 processes left behind when wxWidgets would fail to "notice" window closures properly. * Database loader is now thread-safe and cleans itself up properly on exit. * Added some handy enumeration tools for the gamefixes (prep work for making them commandline controllable). * ... and more prelim commandline work! (actual functional implementations coming very soon) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3212 96395faa-99c1-11dd-bbfe-3dabce05a288 --- common/include/Utilities/wxGuiTools.h | 4 +- pcsx2/CDVD/CDVD.cpp | 6 +- pcsx2/Config.h | 47 +++++- pcsx2/DataBase_Loader.cpp | 5 +- pcsx2/DataBase_Loader.h | 77 ++++++--- pcsx2/Patch.cpp | 19 ++- pcsx2/Pcsx2Config.cpp | 79 +++++++++ pcsx2/R5900.cpp | 35 ++-- pcsx2/System.cpp | 1 - pcsx2/ZipTools/thread_gzip.cpp | 6 +- pcsx2/gui/App.h | 95 ++++++++++- pcsx2/gui/AppConfig.cpp | 6 +- pcsx2/gui/AppConfig.h | 8 - pcsx2/gui/AppCorePlugins.cpp | 8 +- pcsx2/gui/AppInit.cpp | 223 ++++++++++++++++++------- pcsx2/gui/AppMain.cpp | 53 +++--- pcsx2/gui/AppRes.cpp | 1 + pcsx2/gui/ConsoleLogger.cpp | 65 ++++++- pcsx2/gui/MainFrame.cpp | 2 +- pcsx2/gui/Panels/ConfigurationPanels.h | 4 +- pcsx2/gui/Panels/GameDatabasePanel.cpp | 65 +++---- pcsx2/gui/Panels/GameFixesPanel.cpp | 30 +--- 22 files changed, 596 insertions(+), 243 deletions(-) diff --git a/common/include/Utilities/wxGuiTools.h b/common/include/Utilities/wxGuiTools.h index 5172cda977..9405df2a7a 100644 --- a/common/include/Utilities/wxGuiTools.h +++ b/common/include/Utilities/wxGuiTools.h @@ -561,7 +561,9 @@ protected: void OnDialogCreated( wxCommandEvent& evt ); void OnOkCancel(wxCommandEvent& evt); void OnCloseWindow(wxCloseEvent& event); - + + bool ShouldPreventAppExit() const { return false; } + void DoAutoCenter(); }; diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index c7fefeded4..03d09672f2 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -29,8 +29,6 @@ #include "ps2/BiosTools.h" #include "DataBase_Loader.h" -ScopedPtr GameDB; - wxString DiscID; static cdvdStruct cdvd; @@ -356,7 +354,7 @@ static __forceinline void _reloadElfInfo(wxString elfpath) elfptr.Delete(); // Set the Game DataBase to the correct game based on Game Serial Code... - if (GameDB) { + if (DataBase_Loader* GameDB = AppHost_GetGameDatabase()) { wxString gameSerial = DiscID; if (DiscID.IsEmpty()) { // Search for crc if no Serial Code gameSerial = wxString(wxsFormat( L"%8.8x", ElfCRC )); @@ -555,8 +553,6 @@ void cdvdReset() cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9); cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0" cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000); - - if( !GameDB ) GameDB = new DataBase_Loader(); } struct Freeze_v10Compat diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 5b59fe3834..5212614624 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -19,6 +19,25 @@ class IniInterface; +class pxEnumEnd_t { }; +const pxEnumEnd_t pxEnumEnd = {}; + +// [TODO] Add assertion checks to ++/-- operators! +#define ImplementEnumOperators( enumName ) \ + static __forceinline GamefixId& operator++( enumName& src ) { src = (enumName)((int)src+1); return src; } \ + static __forceinline GamefixId& operator--( enumName& src ) { src = (enumName)((int)src-1); return src; } \ + static __forceinline GamefixId operator++( enumName& src, int ) { enumName orig = src; src = (enumName)((int)src+1); return orig; } \ + static __forceinline GamefixId operator--( enumName& src, int ) { enumName orig = src; src = (enumName)((int)src-1); return src; } \ + \ + static __forceinline bool operator<( const enumName& left, const pxEnumEnd_t& ) { return (int)left < enumName##_COUNT; } \ + static __forceinline bool operator!=( const enumName& left, const pxEnumEnd_t& ) { return (int)left != enumName##_COUNT; } \ + static __forceinline bool operator==( const enumName& left, const pxEnumEnd_t& ) { return (int)left == enumName##_COUNT; } \ + \ + static __forceinline void EnumAssertOnBounds( enumName id ) { \ + pxAssume( ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT ) ); } \ + \ + extern const wxChar* EnumToString( enumName id ) + enum PluginsEnum_t { PluginId_GS = 0, @@ -37,6 +56,25 @@ enum PluginsEnum_t PluginId_Mcd }; +enum GamefixId +{ + GamefixId_FIRST = 0, + + Fix_VuAddSub = GamefixId_FIRST, + Fix_VuClipFlag, + Fix_FpuCompare, + Fix_FpuMultiply, + Fix_FpuNegDiv, + Fix_XGKick, + Fix_IpuWait, + Fix_EETiming, + Fix_SkipMpeg, + + GamefixId_COUNT +}; + +ImplementEnumOperators( GamefixId ); + //------------ DEFAULT sseMXCSR VALUES --------------- #define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop" #define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop" @@ -440,6 +478,13 @@ struct Pcsx2Config GamefixOptions() : bitset( 0 ) {} void LoadSave( IniInterface& conf ); + void Set( const wxString& list, bool enabled=true ); + bool Clear( const wxString& list ) { Set( list, false ); } + + bool Get( GamefixId id ) const; + void Set( GamefixId id, bool enabled=true ); + bool Clear( GamefixId id ) { Set( id, false ); } + bool operator ==( const GamefixOptions& right ) const { return OpEqu( bitset ); @@ -562,8 +607,6 @@ TraceLogFilters& SetTraceConfig(); #define CHECK_IOPREC (EmuConfig.Cpu.Recompiler.EnableIOP && GetSysCoreAlloc().IsRecAvailable_IOP()) //------------ SPECIAL GAME FIXES!!! --------------- -#define NUM_OF_GAME_FIXES 9 - #define CHECK_VUADDSUBHACK (EmuConfig.Gamefixes.VuAddSubHack) // Special Fix for Tri-ace games, they use an encryption algorithm that requires VU addi opcode to be bit-accurate. #define CHECK_FPUCOMPAREHACK (EmuConfig.Gamefixes.FpuCompareHack) // Special Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. #define CHECK_VUCLIPFLAGHACK (EmuConfig.Gamefixes.VuClipFlagHack) // Special Fix for Persona games, maybe others. It's to do with the VU clip flag (again). diff --git a/pcsx2/DataBase_Loader.cpp b/pcsx2/DataBase_Loader.cpp index c8302f616f..1e7d1ca54e 100644 --- a/pcsx2/DataBase_Loader.cpp +++ b/pcsx2/DataBase_Loader.cpp @@ -8,7 +8,7 @@ void DataBase_Loader::doError(const wxString& line, key_pair& keyPair, bool doMsg) { if (doMsg) Console.Error("DataBase_Loader: Bad file data [%s]", line.c_str()); - keyPair.key.clear(); + keyPair.Clear(); } // Multiline Sections are in the form of: @@ -47,8 +47,7 @@ bool DataBase_Loader::extractMultiLine(const wxString& line, key_pair& keyPair, } void DataBase_Loader::extract(const wxString& line, key_pair& keyPair, wxInputStream& reader) { - keyPair.key.clear(); - keyPair.value.clear(); + keyPair.Clear(); if( line.IsEmpty() ) return; diff --git a/pcsx2/DataBase_Loader.h b/pcsx2/DataBase_Loader.h index 737702d23a..2dba732cdb 100644 --- a/pcsx2/DataBase_Loader.h +++ b/pcsx2/DataBase_Loader.h @@ -28,6 +28,20 @@ struct key_pair { key_pair(const wxString& _key, const wxString& _value) : key(_key) , value(_value) {} + void Clear() { + key.clear(); + value.clear(); + } + + // Performs case-insensitive compare against the key value. + bool CompareKey( const wxString& cmpto ) const { + return key.CmpNoCase(cmpto) == 0; + } + + bool IsOk() const { + return !key.IsEmpty(); + } + wxString toString() const { if (key[0] == '[') { pxAssumeDev( key.EndsWith(L"]"), "Malformed multiline key detected: missing end bracket!" ); @@ -54,8 +68,17 @@ class Game_Data { public: wxString id; // Serial Identification Code deque kList; // List of all (key, value) pairs for game data - Game_Data(const wxString& _id) + Game_Data(const wxString& _id = wxEmptyString) : id(_id) {} + + void NewSerial( const wxString& _id ) { + id = _id; + kList.clear(); + } + + bool IsOk() const { + return !id.IsEmpty(); + } }; // DataBase_Loader: @@ -83,8 +106,9 @@ protected: const wxString m_emptyString; // empty string for returning stuff .. never modify! wxString m_dest; std::string m_intermediate; + public: - deque gList; // List of all game data + deque gList; // List of all game data Game_Data* curGame; // Current game data wxString header; // Header of the database wxString baseKey; // Key to separate games by ("Serial") @@ -99,34 +123,34 @@ public: wxFFileInputStream reader( file ); key_pair keyPair; wxString s0; - Game_Data* game = NULL; + Game_Data game; try { while(!reader.Eof()) { while(!reader.Eof()) { // Find first game pxReadLine(reader, s0, m_intermediate); extract(s0.Trim(true).Trim(false), keyPair, reader); - if (keyPair.key == key) break; + if (keyPair.CompareKey(key)) break; header += s0 + L'\n'; } - game = new Game_Data(keyPair.value); - game->kList.push_back(keyPair); + game.NewSerial( keyPair.value ); + game.kList.push_back(keyPair); while(!reader.Eof()) { // Fill game data, find new game, repeat... pxReadLine(reader, s0, m_intermediate); extract(s0.Trim(true).Trim(false), keyPair, reader); - if (keyPair.key.IsEmpty()) continue; - if (keyPair.key == key) { + if (!keyPair.IsOk()) continue; + if (keyPair.CompareKey(key)) { gList.push_back(game); - game = new Game_Data(keyPair.value); + game.NewSerial(keyPair.value); } - game->kList.push_back(keyPair); + game.kList.push_back(keyPair); } } } catch( Exception::EndOfStream& ) {} - if (game) gList.push_back(game); + if (game.IsOk()) gList.push_back(game); if (value.IsEmpty()) return; if (setGame(value)) Console.WriteLn(L"DataBase_Loader: Found Game! [%s]", value.c_str()); @@ -135,15 +159,16 @@ public: virtual ~DataBase_Loader() throw() { // deque deletes its contents automatically. + Console.WriteLn( "(GameDB) Destroying..." ); } // Sets the current game to the one matching the serial id given // Returns true if game found, false if not found... bool setGame(const wxString& id) { - deque::iterator it = gList.begin(); + deque::iterator it = gList.begin(); for ( ; it != gList.end(); ++it) { - if (it[0]->id == id) { - curGame = it[0]; + if (it[0].id == id) { + curGame = &it[0]; return true; } } @@ -162,10 +187,10 @@ public: void saveToFile(const wxString& file = L"GameIndex.dbf") { wxFFileOutputStream writer( file ); pxWriteMultiline(writer, header); - deque::iterator it = gList.begin(); + deque::iterator it = gList.begin(); for ( ; it != gList.end(); ++it) { - deque::iterator i = it[0]->kList.begin(); - for ( ; i != it[0]->kList.end(); ++i) { + deque::iterator i = it[0].kList.begin(); + for ( ; i != it[0].kList.end(); ++i) { pxWriteMultiline(writer, i[0].toString() ); } pxWriteLine(writer, L"---------------------------------------------"); @@ -176,11 +201,11 @@ public: // If searchDB is true, it searches the database to see if game already exists. void addGame(const wxString& id, bool searchDB = true) { if (searchDB && setGame(id)) return; - Game_Data* game = new Game_Data(id); - key_pair kp(baseKey, id); - game->kList.push_back(kp); + Game_Data game(id); + key_pair kp(baseKey, id); + game.kList.push_back(kp); gList.push_back(game); - curGame = game; + curGame = &(gList.end()-1)[0]; } // Searches the current game's data to see if the given key exists @@ -188,7 +213,7 @@ public: if (curGame) { deque::iterator it = curGame->kList.begin(); for ( ; it != curGame->kList.end(); ++it) { - if (it[0].key == key) { + if (it[0].CompareKey(key)) { return true; } } @@ -202,7 +227,7 @@ public: if (curGame) { deque::iterator it = curGame->kList.begin(); for ( ; it != curGame->kList.end(); ++it) { - if (it[0].key == key) { + if (it[0].CompareKey(key)) { curGame->kList.erase(it); return; } @@ -216,7 +241,7 @@ public: if (curGame) { deque::iterator it = curGame->kList.begin(); for ( ; it != curGame->kList.end(); ++it) { - if (it[0].key == key) { + if (it[0].CompareKey(key)) { return it[0].value; } } @@ -273,7 +298,7 @@ public: if (curGame) { deque::iterator it = curGame->kList.begin(); for ( ; it != curGame->kList.end(); ++it) { - if (it[0].key == key) { + if (it[0].CompareKey(key)) { it[0].value = value; return; } @@ -357,4 +382,4 @@ static int loadGameSettings(DataBase_Loader* gameDB) { return 0; } -extern ScopedPtr GameDB; +extern DataBase_Loader* AppHost_GetGameDatabase(); \ No newline at end of file diff --git a/pcsx2/Patch.cpp b/pcsx2/Patch.cpp index b88eac3986..f2aa235c83 100644 --- a/pcsx2/Patch.cpp +++ b/pcsx2/Patch.cpp @@ -138,14 +138,17 @@ int InitPatches(const wxString& name) const wxString crc( L"[patches = " + name + L"]" ); patchnumber = 0; - if (GameDB && GameDB->gameLoaded()) { - if (GameDB->sectionExists(L"patches", name)) { - patch = GameDB->getSection(L"patches", name); - patchFound = true; - } - else if (GameDB->keyExists(L"[patches]")) { - patch = GameDB->getString(L"[patches]"); - patchFound = true; + if (DataBase_Loader* GameDB = AppHost_GetGameDatabase() ) + { + if(GameDB->gameLoaded()) { + if (GameDB->sectionExists(L"patches", name)) { + patch = GameDB->getSection(L"patches", name); + patchFound = true; + } + else if (GameDB->keyExists(L"[patches]")) { + patch = GameDB->getString(L"[patches]"); + patchFound = true; + } } } diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 1b992e2321..fd956e143d 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -246,6 +246,85 @@ void Pcsx2Config::GSOptions::LoadSave( IniInterface& ini ) IniEntry( FramesToSkip ); } +const wxChar *const tbl_GamefixNames[] = +{ + L"VuAddSub", + L"VuClipFlag", + L"FpuCompare", + L"FpuMul", + L"FpuNegDiv", + L"XGKick", + L"IpuWait", + L"EETiming", + L"SkipMpeg" +}; + +const __forceinline wxChar* EnumToString( GamefixId id ) +{ + return tbl_GamefixNames[id]; +} + +// Enables a full list of gamefixes. The list can be either comma or pipe-delimited. +// Example: "XGKick,IpuWait" or "EEtiming,FpuCompare" +// If an unrecognized tag is encountered, a warning is printed to the console, but no error +// is generated. This allows the system to function in the event that future versions of +// PCSX2 remove old hacks once they become obsolete. +void Pcsx2Config::GamefixOptions::Set( const wxString& list, bool enabled ) +{ + wxStringTokenizer izer( list, L",|", wxTOKEN_STRTOK ); + + while( izer.HasMoreTokens() ) + { + wxString token( izer.GetNextToken() ); + + GamefixId i; + for (i=GamefixId_FIRST; i < pxEnumEnd; ++i) + { + if( token.CmpNoCase( EnumToString(i) ) == 0 ) break; + } + if( i < pxEnumEnd ) Set( i ); + } +} + +void Pcsx2Config::GamefixOptions::Set( GamefixId id, bool enabled ) +{ + EnumAssertOnBounds( id ); + switch(id) + { + case Fix_VuAddSub: VuAddSubHack = enabled; break; + case Fix_VuClipFlag: VuClipFlagHack = enabled; break; + case Fix_FpuCompare: FpuCompareHack = enabled; break; + case Fix_FpuMultiply: FpuMulHack = enabled; break; + case Fix_FpuNegDiv: FpuNegDivHack = enabled; break; + case Fix_XGKick: XgKickHack = enabled; break; + case Fix_IpuWait: IPUWaitHack = enabled; break; + case Fix_EETiming: EETimingHack = enabled; break; + case Fix_SkipMpeg: SkipMPEGHack = enabled; break; + + jNO_DEFAULT; + } +} + +bool Pcsx2Config::GamefixOptions::Get( GamefixId id ) const +{ + EnumAssertOnBounds( id ); + switch(id) + { + case Fix_VuAddSub: return VuAddSubHack; + case Fix_VuClipFlag: return VuClipFlagHack; + case Fix_FpuCompare: return FpuCompareHack; + case Fix_FpuMultiply: return FpuMulHack; + case Fix_FpuNegDiv: return FpuNegDivHack; + case Fix_XGKick: return XgKickHack; + case Fix_IpuWait: return IPUWaitHack; + case Fix_EETiming: return EETimingHack; + case Fix_SkipMpeg: return SkipMPEGHack; + + jNO_DEFAULT + } + return false; // unreachable, but we still need to suppress warnings >_< +} + void Pcsx2Config::GamefixOptions::LoadSave( IniInterface& ini ) { GamefixOptions defaults; diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index c95f19352e..abd0c6081c 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -585,23 +585,26 @@ void __fastcall eeGameStarting() wxString gameFixes = L""; wxString gameCheats = L""; - if (GameDB && GameDB->gameLoaded()) { - int compat = GameDB->getInt("Compat"); - gameName = GameDB->getString("Name"); - gameName += L" (" + GameDB->getString("Region") + L")"; - gameCompat = L" [Status = "+compatToStringWX(compat)+L"]"; - } - - if (EmuConfig.EnablePatches) { - int patches = InitPatches(gameCRC); - if (patches) { - wxString pString( wxsFormat( L"%d", patches ) ); - gamePatch = L" [Patches = " + pString + L"]"; + if (DataBase_Loader* GameDB = AppHost_GetGameDatabase() ) + { + if (GameDB->gameLoaded()) { + int compat = GameDB->getInt("Compat"); + gameName = GameDB->getString("Name"); + gameName += L" (" + GameDB->getString("Region") + L")"; + gameCompat = L" [Status = "+compatToStringWX(compat)+L"]"; } - int fixes = loadGameSettings(GameDB); - if (fixes) { - wxString pString( wxsFormat( L"%d", fixes ) ); - gameFixes = L" [Fixes = " + pString + L"]"; + + if (EmuConfig.EnablePatches) { + int patches = InitPatches(gameCRC); + if (patches) { + wxString pString( wxsFormat( L"%d", patches ) ); + gamePatch = L" [Patches = " + pString + L"]"; + } + int fixes = loadGameSettings(GameDB); + if (fixes) { + wxString pString( wxsFormat( L"%d", fixes ) ); + gameFixes = L" [Fixes = " + pString + L"]"; + } } } diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index 0b80c37e8c..a2be1c1f93 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -328,7 +328,6 @@ void SysCoreAllocations::CleanupMess() throw() { try { - GameDB.Delete(); closeNewVif(0); closeNewVif(1); diff --git a/pcsx2/ZipTools/thread_gzip.cpp b/pcsx2/ZipTools/thread_gzip.cpp index bf5c655c76..0a6c4d6ca3 100644 --- a/pcsx2/ZipTools/thread_gzip.cpp +++ b/pcsx2/ZipTools/thread_gzip.cpp @@ -22,7 +22,11 @@ BaseCompressThread::~BaseCompressThread() throw() { - if( m_PendingSaveFlag ) wxGetApp().ClearPendingSave(); + if( m_PendingSaveFlag ) + { + wxGetApp().ClearPendingSave(); + m_PendingSaveFlag = false; + } } void BaseCompressThread::SetPendingSave() diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index f0044a48d9..3b6539e3c7 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -26,6 +26,7 @@ #include "AppCommon.h" #include "AppCoreThread.h" #include "RecentIsoList.h" +#include "DataBase_Loader.h" #include "System.h" #include "System/SysThreads.h" @@ -317,6 +318,7 @@ struct pxAppResources ScopedPtr ToolbarImages; ScopedPtr IconBundle; ScopedPtr Bitmap_Logo; + ScopedPtr GameDB; pxAppResources(); virtual ~pxAppResources() throw() { } @@ -359,6 +361,78 @@ public: double GetFramerate() const; }; +class StartupOptions +{ +public: + bool ForceWizard; + bool ForceConsole; + + // Disables the fast boot option when auto-running games. This option only applies + // if SysAutoRun is also true. + bool NoFastBoot; + + // Specifies the Iso file to boot; used only if SysAutoRun is enabled and CdvdSource + // is set to ISO. + wxString IsoFile; + + // Specifies the CDVD source type to use when AutoRunning + CDVD_SourceType CdvdSource; + + // Indicates if PCSX2 should autorun the configured CDVD source and/or ISO file. + bool SysAutoRun; + + StartupOptions() + { + ForceWizard = false; + NoFastBoot = false; + ForceConsole = false; + SysAutoRun = false; + CdvdSource = CDVDsrc_NoDisc; + } +}; + + +class CommandlineOverrides +{ +public: + AppConfig::FilenameOptions Filenames; + wxDirName SettingsFolder; + wxFileName SettingsFile; + + bool DisableSpeedhacks; + + // Note that gamefixes in this array should only be honored if the + // "HasCustomGamefixes" boolean is also enabled. + bool UseGamefix[GamefixId_COUNT]; + bool ApplyCustomGamefixes; + +public: + CommandlineOverrides() + { + DisableSpeedhacks = false; + ApplyCustomGamefixes = false; + } + + // Returns TRUE if either speedhacks or gamefixes are being overridden. + bool HasCustomHacks() const + { + return DisableSpeedhacks || ApplyCustomGamefixes; + } + + bool HasSettingsOverride() const + { + return SettingsFolder.IsOk() || SettingsFile.IsOk(); + } + + bool HasPluginsOverride() const + { + for( int i=0; i m_StdoutRedirHandle; ScopedPtr m_StderrRedirHandle; @@ -459,11 +539,13 @@ protected: ScopedPtr m_RecentIsoList; ScopedPtr m_Resources; + Threading::Mutex m_mtx_Resources; + Threading::Mutex m_mtx_LoadingGameDB; + +public: // Executor Thread for complex VM/System tasks. This thread is used to execute such tasks // in parallel to the main message pump, to allow the main pump to run without fear of // blocked threads stalling the GUI. - -public: ExecutorThread SysExecutorThread; ScopedPtr m_CoreAllocs; @@ -535,6 +617,8 @@ public: { return m_Resources->ImageId; } + + DataBase_Loader* GetGameDatabase(); // -------------------------------------------------------------------------- // Overrides of wxApp virtuals: @@ -546,17 +630,23 @@ public: void OnInitCmdLine( wxCmdLineParser& parser ); bool OnCmdLineParsed( wxCmdLineParser& parser ); bool OnCmdLineError( wxCmdLineParser& parser ); + bool ParseOverrides( wxCmdLineParser& parser ); #ifdef __WXDEBUG__ void OnAssertFailure( const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg ); #endif + Threading::MutexRecursive m_mtx_ProgramLog; + ConsoleLogFrame* m_ptr_ProgramLog; + // ---------------------------------------------------------------------------- // Console / Program Logging Helpers // ---------------------------------------------------------------------------- ConsoleLogFrame* GetProgramLog(); const ConsoleLogFrame* GetProgramLog() const; void ProgramLog_PostEvent( wxEvent& evt ); + Threading::Mutex& GetProgramLogLock(); + void EnableAllLogging(); void DisableWindowLogging() const; void DisableDiskLogging() const; @@ -577,6 +667,7 @@ protected: void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event) const; void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event); + void OnScheduledTermination( wxTimerEvent& evt ); void OnEmuKeyDown( wxKeyEvent& evt ); void OnSysExecutorTaskTimeout( wxTimerEvent& evt ); void OnDestroyWindow( wxWindowDestroyEvent& evt ); diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 9bc375f4e9..1524a9eb54 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -331,12 +331,16 @@ wxDirName GetLogFolder() wxDirName GetSettingsFolder() { + if( wxGetApp().Overrides.SettingsFolder.IsOk() ) + return wxGetApp().Overrides.SettingsFolder; + return UseDefaultSettingsFolder ? PathDefs::GetSettings() : SettingsFolder; } wxString GetSettingsFilename() { - return GetSettingsFolder().Combine( FilenameDefs::GetConfig() ).GetFullPath(); + wxFileName fname( wxGetApp().Overrides.SettingsFile.IsOk() ? wxGetApp().Overrides.SettingsFile : FilenameDefs::GetConfig() ); + return GetSettingsFolder().Combine( fname ).GetFullPath(); } diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index 259a9ebf81..4cd0e14e29 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -254,14 +254,6 @@ public: void LoadSaveMemcards( IniInterface& ini ); }; -struct ConfigOverrides -{ - AppConfig::FilenameOptions Filenames; - wxString SettingsFolder; -}; - -extern ConfigOverrides OverrideOptions; - extern wxFileConfig* OpenFileConfig( const wxString& filename ); extern void RelocateLogfile(); extern void AppConfig_OnChangedSettingsFolder( bool overwrite = false ); diff --git a/pcsx2/gui/AppCorePlugins.cpp b/pcsx2/gui/AppCorePlugins.cpp index 0a884270b3..7f8ae5d112 100644 --- a/pcsx2/gui/AppCorePlugins.cpp +++ b/pcsx2/gui/AppCorePlugins.cpp @@ -91,7 +91,7 @@ static void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] ) { const PluginInfo* pi = tbl_PluginInfo; do { - passins[pi->id] = OverrideOptions.Filenames[pi->id].GetFullPath(); + passins[pi->id] = wxGetApp().Overrides.Filenames[pi->id].GetFullPath(); if( passins[pi->id].IsEmpty() || !wxFileExists( passins[pi->id] ) ) passins[pi->id] = g_Conf->FullpathTo( pi->id ); @@ -101,6 +101,9 @@ static void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] ) typedef void (AppPluginManager::*FnPtr_AppPluginManager)(); typedef void (AppPluginManager::*FnPtr_AppPluginPid)( PluginsEnum_t pid ); +// -------------------------------------------------------------------------------------- +// SysExecEvent_AppPluginManager +// -------------------------------------------------------------------------------------- class SysExecEvent_AppPluginManager : public SysExecEvent { protected: @@ -122,6 +125,9 @@ protected: } }; +// -------------------------------------------------------------------------------------- +// LoadSinglePluginEvent +// -------------------------------------------------------------------------------------- class LoadSinglePluginEvent : public pxInvokeActionEvent { typedef pxInvokeActionEvent _parent; diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index f50232fe57..ad90d8ff94 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -28,11 +28,6 @@ using namespace pxSizerFlags; -static bool m_ForceWizard = false; -static bool m_UseGUI = false; -static bool m_NoFastBoot = false; -static bool m_DisableSpeedhacks = false; - static void CpuCheckSSE2() { if( x86caps.hasStreamingSIMD2Extensions ) return; @@ -110,7 +105,7 @@ void Pcsx2App::ReadUserModeSettings() wxString groupname( wxsFormat( L"CWD.%08x", hashres ) ); bool hasGroup = conf_usermode->HasGroup( groupname ); - bool forceWiz = m_ForceWizard || !hasGroup; + bool forceWiz = Startup.ForceWizard || !hasGroup; if( !forceWiz ) { @@ -208,26 +203,28 @@ void Pcsx2App::OpenMainFrame() MainEmuFrame* mainFrame = new MainEmuFrame( NULL, L"PCSX2" ); m_id_MainFrame = mainFrame->GetId(); - if( wxWindow* deleteme = GetProgramLog() ) - { - deleteme->Destroy(); - g_Conf->ProgLogBox.Visible = true; - m_id_ProgramLogBox = wxID_ANY; - PostIdleAppMethod( &Pcsx2App::OpenProgramLog ); - } + PostAppMethod( &Pcsx2App::OpenProgramLog ); SetTopWindow( mainFrame ); // not really needed... - SetExitOnFrameDelete( true ); // but being explicit doesn't hurt... + SetExitOnFrameDelete( false ); // but being explicit doesn't hurt... mainFrame->Show(); } void Pcsx2App::OpenProgramLog() { - if( GetProgramLog() != NULL ) return; + if( ConsoleLogFrame* frame = GetProgramLog() ) + { + //pxAssume( ); + return; + } + wxWindow* m_current_focus = wxGetActiveWindow(); - m_id_ProgramLogBox = (new ConsoleLogFrame( GetMainFramePtr(), L"PCSX2 Program Log", g_Conf->ProgLogBox ))->GetId(); + + ScopedLock lock( m_mtx_ProgramLog ); + m_ptr_ProgramLog = new ConsoleLogFrame( GetMainFramePtr(), L"PCSX2 Program Log", g_Conf->ProgLogBox ); + m_id_ProgramLogBox = m_ptr_ProgramLog->GetId(); EnableAllLogging(); - + if( m_current_focus ) m_current_focus->SetFocus(); } @@ -330,21 +327,29 @@ void Pcsx2App::OnInitCmdLine( wxCmdLineParser& parser ) _("All options are for the current session only and will not be saved.\n") ); + wxString fixlist( L" " ); + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + { + if( i != GamefixId_FIRST ) fixlist += L","; + fixlist += EnumToString(i); + } + parser.AddParam( _("IsoFile"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL ); + parser.AddSwitch( L"h", L"help", _("displays this list of command line options"), wxCMD_LINE_OPTION_HELP ); + parser.AddSwitch( wxEmptyString,L"console", _("forces the program log/console to be visible") ); - parser.AddSwitch( L"h", L"help", _("displays this list of command line options"), wxCMD_LINE_OPTION_HELP ); + parser.AddSwitch( wxEmptyString,L"nogui", _("disables display of the gui while running games") ); + parser.AddOption( wxEmptyString,L"elf", _("executes an ELF image"), wxCMD_LINE_VAL_STRING ); + parser.AddSwitch( wxEmptyString,L"nodisc", _("boots an empty dvd tray; use to enter the PS2 system menu") ); + parser.AddSwitch( wxEmptyString,L"usecd", _("boots from the CDVD plugin (overrides IsoFile parameter)") ); - parser.AddSwitch( wxEmptyString,L"nogui", _("disables display of the gui while running games") ); - parser.AddOption( wxEmptyString,L"elf", _("executes an ELF image"), wxCMD_LINE_VAL_STRING ); - parser.AddSwitch( wxEmptyString,L"nodisc", _("boots an empty dvd tray; use to enter the PS2 system menu") ); - parser.AddSwitch( wxEmptyString,L"usecd", _("boots from the CDVD plugin (overrides IsoFile parameter)") ); + parser.AddSwitch( wxEmptyString,L"fullboot", _("disables fast booting") ); + parser.AddSwitch( wxEmptyString,L"nohacks", _("disables all speedhacks") ); + parser.AddSwitch( wxEmptyString,L"gamefixes", _("use the specified comma or pipe-delimited list of gamefixes.") + fixlist ); - parser.AddSwitch( wxEmptyString,L"fullboot",_("disables fast booting") ); - parser.AddSwitch( wxEmptyString,L"nohacks", _("disables all speedhacks") ); - - parser.AddOption( wxEmptyString,L"cfgpath", _("changes the configuration file path"), wxCMD_LINE_VAL_STRING ); - parser.AddOption( wxEmptyString,L"cfg", _("specifies the PCSX2 configuration file to use"), wxCMD_LINE_VAL_STRING ); - parser.AddSwitch( wxEmptyString,L"forcewiz",_("forces PCSX2 to start the First-time Wizard") ); + parser.AddOption( wxEmptyString,L"cfgpath", _("changes the configuration file path"), wxCMD_LINE_VAL_STRING ); + parser.AddOption( wxEmptyString,L"cfg", _("specifies the PCSX2 configuration file to use"), wxCMD_LINE_VAL_STRING ); + parser.AddSwitch( wxEmptyString,L"forcewiz", _("forces PCSX2 to start the First-time Wizard") ); const PluginInfo* pi = tbl_PluginInfo; do { parser.AddOption( wxEmptyString, pi->GetShortname().Lower(), @@ -361,50 +366,85 @@ bool Pcsx2App::OnCmdLineError( wxCmdLineParser& parser ) return false; } -bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser ) +bool Pcsx2App::ParseOverrides( wxCmdLineParser& parser ) { - if( parser.GetParamCount() >= 1 ) + wxString dest; + + if( parser.Found( L"cfgpath", &dest ) && !dest.IsEmpty() ) { - // [TODO] : Unnamed parameter is taken as an "autorun" option for a cdvd/iso. - parser.GetParam( 0 ); + Console.Warning( L"Config path override: " + dest ); + Overrides.SettingsFolder = dest; } - // Suppress wxWidgets automatic options parsing since none of them pertain to PCSX2 needs. - //wxApp::OnCmdLineParsed( parser ); - - m_UseGUI = !parser.Found(L"nogui"); - m_DisableSpeedhacks = parser.Found(L"nohacks"); - m_NoFastBoot = parser.Found(L"fullboot"); - m_ForceWizard = parser.Found( L"forcewiz" ); - - wxString cfgPathOverride; - //if( parser.Found(L"cfgpath", cfgPathOverride ) ) + if( parser.Found( L"cfg", &dest ) && !dest.IsEmpty() ) { + Console.Warning( L"Config file override: " + dest ); + Overrides.SettingsFile = dest; } + Overrides.DisableSpeedhacks = parser.Found(L"nohacks"); + const PluginInfo* pi = tbl_PluginInfo; do { - wxString dest; if( !parser.Found( pi->GetShortname().Lower(), &dest ) ) continue; - OverrideOptions.Filenames.Plugins[pi->id] = dest; - if( wxFileExists( dest ) ) Console.Warning( pi->GetShortname() + L" override: " + dest ); else { - bool result = Msgbox::OkCancel( - wxsFormat( _("Plugin Override Error! Specified %s plugin does not exist:\n\n"), pi->GetShortname().c_str() ) + - dest + - _("Press OK to use the default configured plugin, or Cancel to close."), - _("Plugin Override Error - PCSX2"), wxICON_ERROR - ); + wxDialogWithHelpers okcan( NULL, _("Plugin Override Error - PCSX2") ); - if( !result ) return false; + okcan += okcan.Heading( wxsFormat( + _("%s Plugin Override Error! The following file does not exist or is not a valid %s plugin:\n\n"), + pi->GetShortname().c_str(), pi->GetShortname().c_str() + ) ); + + okcan += okcan.GetCharHeight(); + okcan += okcan.Text(dest); + okcan += okcan.GetCharHeight(); + okcan += okcan.Heading(_("Press OK to use the default configured plugin, or Cancel to close PCSX2.")); + + if( wxID_CANCEL == pxIssueConfirmation( okcan, MsgButtons().OKCancel() ) ) return false; } - } while( ++pi, pi->shortname != NULL ); + + Overrides.Filenames.Plugins[pi->id] = dest; - parser.Found( L"cfgpath", &OverrideOptions.SettingsFolder ); + } while( ++pi, pi->shortname != NULL ); + + return true; +} + +bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser ) +{ + if( parser.Found(L"console") ) + { + Startup.ForceConsole = true; + OpenProgramLog(); + } + + // Suppress wxWidgets automatic options parsing since none of them pertain to PCSX2 needs. + //wxApp::OnCmdLineParsed( parser ); + + m_UseGUI = !parser.Found(L"nogui"); + + if( !ParseOverrides(parser) ) return false; + + // --- Parse Startup/Autoboot options --- + + Startup.NoFastBoot = parser.Found(L"fullboot"); + Startup.ForceWizard = parser.Found(L"forcewiz"); + + if( parser.GetParamCount() >= 1 ) + { + Startup.IsoFile = parser.GetParam( 0 ); + Startup.SysAutoRun = true; + } + + if( parser.Found(L"usecd") ) + { + Startup.CdvdSource = CDVDsrc_Plugin; + Startup.SysAutoRun = true; + } return true; } @@ -458,8 +498,23 @@ bool Pcsx2App::OnInit() SysExecutorThread.Start(); DetectCpuAndUserMode(); - PostAppMethod( &Pcsx2App::OpenMainFrame ); - PostAppMethod( &Pcsx2App::OpenProgramLog ); + if( Startup.ForceConsole ) g_Conf->ProgLogBox.Visible = true; + + // Set Manual Exit Handling + // ---------------------------- + // PCSX2 has a lot of event handling logistics, so we *cannot* depend on wxWidgets automatic event + // loop termination code. We have a much safer system in place that continues to process messages + // until all "important" threads are closed out -- not just until the main frame is closed(-ish). + m_timer_Termination = new wxTimer( this, wxID_ANY ); + Connect( m_timer_Termination->GetId(), wxEVT_TIMER, wxTimerEventHandler(Pcsx2App::OnScheduledTermination) ); + SetExitOnFrameDelete( false ); + + + // Start GUI and/or Direct Emulation + // ------------------------------------- + if( m_UseGUI ) + PostAppMethod( &Pcsx2App::OpenMainFrame ); + PostAppMethod( &Pcsx2App::AllocateCoreStuffs ); } // ---------------------------------------------------------------------------- @@ -491,6 +546,54 @@ bool Pcsx2App::OnInit() return true; } +static int m_term_threshold = 20; + +void Pcsx2App::OnScheduledTermination( wxTimerEvent& evt ) +{ + if( !pxAssertDev( m_ScheduledTermination, "Scheduled Termination check is inconsistent with ScheduledTermination status." ) ) + { + m_timer_Termination->Stop(); + return; + } + + if( m_PendingSaves != 0 ) + { + if( --m_term_threshold > 0 ) + { + Console.WriteLn( "(App) %d saves are still pending; exit postponed...", m_PendingSaves ); + return; + } + + Console.Error( "(App) %s pending saves have exceeded OnExit threshold and are being prematurely terminated!", m_PendingSaves ); + } + + m_timer_Termination->Stop(); + Exit(); +} + + +// Common exit handler which can be called from any event (though really it should +// be called only from CloseWindow handlers since that's the more appropriate way +// to handle cancelable window closures) +// +// returns true if the app can close, or false if the close event was canceled by +// the glorious user, whomever (s)he-it might be. +void Pcsx2App::PrepForExit() +{ + if( m_ScheduledTermination ) return; + m_ScheduledTermination = true; + + SysExecutorThread.ShutdownQueue(); + DispatchEvent( AppStatus_Exiting ); + + m_timer_Termination->Start( 500 ); + + // This should be called by OnExit(), but sometimes wxWidgets fails to call OnExit(), so + // do it here just in case (no harm anyway -- OnExit is the next logical step after + // CloseWindow returns true from the TopLevel window). + //CleanupRestartable(); +} + // This cleanup procedure can only be called when the App message pump is still active. // OnExit() must use CleanupOnExit instead. void Pcsx2App::CleanupRestartable() @@ -499,13 +602,9 @@ void Pcsx2App::CleanupRestartable() ShutdownPlugins(); SysExecutorThread.ShutdownQueue(); - - //PingDispatcher( "Cleanup" ); - //DeletionDispatcher(); IdleEventDispatcher( L"Cleanup" ); - if( g_Conf ) - AppSaveSettings(); + if( g_Conf ) AppSaveSettings(); } // This cleanup handler can be called from OnExit (it doesn't need a running message pump), @@ -561,7 +660,6 @@ void Pcsx2App::CleanupResources() int Pcsx2App::OnExit() { CleanupOnExit(); - return wxApp::OnExit(); } @@ -610,6 +708,7 @@ Pcsx2App::Pcsx2App() m_id_MainFrame = wxID_ANY; m_id_GsFrame = wxID_ANY; m_id_ProgramLogBox = wxID_ANY; + m_ptr_ProgramLog = NULL; SetAppName( L"pcsx2" ); BuildCommandHash(); diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 7928400559..6da400906e 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -47,7 +47,6 @@ wxDirName Logs; bool UseDefaultLogs = true; ScopedPtr g_Conf; -ConfigOverrides OverrideOptions; template int AppOpenModalDialog( wxWindow* parent=NULL ) @@ -488,12 +487,18 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& } } +// A call to this method informs the app that there is a pending save operation that must be +// finished prior to exiting the app, or else data loss will occur. Any call to this method +// should be matched by a call to ClearPendingSave(). void Pcsx2App::StartPendingSave() { if( PostAppMethodMyself(&Pcsx2App::StartPendingSave) ) return; ++m_PendingSaves; } +// If this method is called inappropriately then the entire pending save system will become +// unreliable and data loss can occur on app exit. Devel and debug builds will assert if +// such calls are detected (though the detection is far from fool-proof). void Pcsx2App::ClearPendingSave() { if( PostAppMethodMyself(&Pcsx2App::ClearPendingSave) ) return; @@ -508,38 +513,6 @@ void Pcsx2App::ClearPendingSave() } } - -// Common exit handler which can be called from any event (though really it should -// be called only from CloseWindow handlers since that's the more appropriate way -// to handle cancelable window closures) -// -// returns true if the app can close, or false if the close event was canceled by -// the glorious user, whomever (s)he-it might be. -void Pcsx2App::PrepForExit() -{ - SysExecutorThread.ShutdownQueue(); - - //SysExecutorThread.Cancel(); - DispatchEvent( AppStatus_Exiting ); - - if( m_PendingSaves != 0 ) - { - // When the thread finishes, it will call ClearPendingSave, which in turn will - // exit the app once all pending saves have "logged out." (if one does not track - // itself using our PendingSaves feature, it would be lost -- too bad!) - - Console.WriteLn( "App: Saves are pending; exit postponed..." ); - SetExitOnFrameDelete( false ); - m_ScheduledTermination = true; - return; - } - - // This should be called by OnExit(), but sometimes wxWidgets fails to call OnExit(), so - // do it here just in case (no harm anyway -- OnExit is the next logical step after - // CloseWindow returns true from the TopLevel window). - CleanupRestartable(); -} - // This method generates debug assertions if the MainFrame handle is NULL (typically // indicating that PCSX2 is running in NoGUI mode, or that the main frame has been // closed). In most cases you'll want to use HasMainFrame() to test for thread @@ -1013,3 +986,17 @@ SysCoreAllocations& GetSysCoreAlloc() { return *wxGetApp().m_CoreAllocs; } + +DataBase_Loader* Pcsx2App::GetGameDatabase() +{ + pxAppResources& res( GetResourceCache() ); + + ScopedLock lock( m_mtx_LoadingGameDB ); + if( !res.GameDB ) res.GameDB = new DataBase_Loader(); + return res.GameDB; +} + +DataBase_Loader* AppHost_GetGameDatabase() +{ + return wxGetApp().GetGameDatabase(); +} \ No newline at end of file diff --git a/pcsx2/gui/AppRes.cpp b/pcsx2/gui/AppRes.cpp index b7ebd7dcf9..2878de05e5 100644 --- a/pcsx2/gui/AppRes.cpp +++ b/pcsx2/gui/AppRes.cpp @@ -89,6 +89,7 @@ RecentIsoManager& Pcsx2App::GetRecentIsoManager() pxAppResources& Pcsx2App::GetResourceCache() { + ScopedLock lock( m_mtx_Resources ); if( !m_Resources ) m_Resources = new pxAppResources(); diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index 13e0e64171..0269457f4b 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -141,12 +141,15 @@ static bool OpenLogFile(wxFile& file, wxString& filename, wxWindow *parent) return file.Create(filename); } -// ------------------------------------------------------------------------ +// -------------------------------------------------------------------------------------- +// ConsoleLogFrame::ColorArray (implementations) +// -------------------------------------------------------------------------------------- + // fontsize - size of the font specified in points. // (actual font used is the system-selected fixed-width font) // -ConsoleLogFrame::ColorArray::ColorArray( int fontsize ) : - m_table( ConsoleColors_Count ) +ConsoleLogFrame::ColorArray::ColorArray( int fontsize ) + : m_table( ConsoleColors_Count ) { Create( fontsize ); } @@ -225,7 +228,37 @@ enum MenuIDs_t MenuID_FontSize_Huge, }; -// ------------------------------------------------------------------------ +// -------------------------------------------------------------------------------------- +// ScopedLogLock (implementations) +// -------------------------------------------------------------------------------------- +class ScopedLogLock : ScopedLock +{ +public: + ConsoleLogFrame* WindowPtr; + +public: + ScopedLogLock() + : ScopedLock( ((Pcsx2App&)*wxTheApp).GetProgramLogLock() ) + { + WindowPtr = ((Pcsx2App&)*wxTheApp).m_ptr_ProgramLog; + } + + virtual ~ScopedLogLock() throw() {} + + bool HasWindow() const + { + return WindowPtr != NULL; + } + + ConsoleLogFrame& GetWindow() const + { + return *WindowPtr; + } +}; + +// -------------------------------------------------------------------------------------- +// ConsoleLogFrame (implementations) +// -------------------------------------------------------------------------------------- ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, AppConfig::ConsoleLogOptions& options ) : wxFrame(parent, wxID_ANY, title) , m_conf( options ) @@ -333,6 +366,7 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A ConsoleLogFrame::~ConsoleLogFrame() { + ScopedLogLock locker; wxGetApp().OnProgramLogClosed( GetId() ); } @@ -776,6 +810,11 @@ const IConsoleWriter ConsoleWriter_File = ConsoleToFile_SetTitle, }; +Mutex& Pcsx2App::GetProgramLogLock() +{ + return m_mtx_ProgramLog; +} + // -------------------------------------------------------------------------------------- // ConsoleToWindow Implementations // -------------------------------------------------------------------------------------- @@ -798,7 +837,8 @@ template< const IConsoleWriter& secondary > static void __concall ConsoleToWindow_Newline() { secondary.Newline(); - ((Pcsx2App&)*wxTheApp).GetProgramLog()->Newline(); + ScopedLogLock locker; + if( locker.WindowPtr ) locker.WindowPtr->Newline(); } template< const IConsoleWriter& secondary > @@ -806,7 +846,9 @@ static void __concall ConsoleToWindow_DoWrite( const wxString& fmt ) { if( secondary.DoWrite != NULL ) secondary.DoWrite( fmt ); - ((Pcsx2App&)*wxTheApp).GetProgramLog()->Write( Console.GetColor(), fmt ); + + ScopedLogLock locker; + if( locker.WindowPtr ) locker.WindowPtr->Write( Console.GetColor(), fmt ); } template< const IConsoleWriter& secondary > @@ -814,7 +856,9 @@ static void __concall ConsoleToWindow_DoWriteLn( const wxString& fmt ) { if( secondary.DoWriteLn != NULL ) secondary.DoWriteLn( fmt ); - ((Pcsx2App&)*wxTheApp).GetProgramLog()->Write( Console.GetColor(), fmt + L"\n" ); + + ScopedLogLock locker; + if( locker.WindowPtr ) locker.WindowPtr->Write( Console.GetColor(), fmt + L'\n' ); } typedef void __concall DoWriteFn(const wxString&); @@ -843,7 +887,9 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile = void Pcsx2App::EnableAllLogging() { - const bool logBoxOpen = (GetProgramLog() != NULL); + ScopedLock lock( m_mtx_ProgramLog ); + + const bool logBoxOpen = (m_ptr_ProgramLog != NULL); const IConsoleWriter* newHandler = NULL; if( emuLog ) @@ -888,6 +934,7 @@ void Pcsx2App::DisableDiskLogging() const void Pcsx2App::DisableWindowLogging() const { + ScopedLock lock( m_mtx_ProgramLog ); Console_SetActiveHandler( (emuLog!=NULL) ? (IConsoleWriter&)ConsoleWriter_File : (IConsoleWriter&)ConsoleWriter_Stdout ); - Threading::Sleep( 5 ); + //Threading::Sleep( 5 ); } diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp index a54cf15523..e37b699f5a 100644 --- a/pcsx2/gui/MainFrame.cpp +++ b/pcsx2/gui/MainFrame.cpp @@ -94,13 +94,13 @@ void MainEmuFrame::OnCloseWindow(wxCloseEvent& evt) } - wxGetApp().PrepForExit(); sApp.OnMainFrameClosed( GetId() ); if( m_menubar.FindItem(MenuId_IsoSelector) ) m_menuCDVD.Remove(MenuId_IsoSelector); RemoveEventHandler( &wxGetApp().GetRecentIsoManager() ); + wxGetApp().PostIdleAppMethod( &Pcsx2App::PrepForExit ); evt.Skip(); } diff --git a/pcsx2/gui/Panels/ConfigurationPanels.h b/pcsx2/gui/Panels/ConfigurationPanels.h index 9c04d42b42..a569e38e96 100644 --- a/pcsx2/gui/Panels/ConfigurationPanels.h +++ b/pcsx2/gui/Panels/ConfigurationPanels.h @@ -330,7 +330,7 @@ namespace Panels class GameFixesPanel : public BaseApplicableConfigPanel { protected: - pxCheckBox* m_checkbox[NUM_OF_GAME_FIXES]; + pxCheckBox* m_checkbox[GamefixId_COUNT]; pxCheckBox* m_check_Enable; public: @@ -358,7 +358,7 @@ namespace Panels wxTextCtrl* compatBox; wxTextCtrl* commentBox; wxTextCtrl* patchesBox; - pxCheckBox* gameFixes[NUM_OF_GAME_FIXES]; + pxCheckBox* gameFixes[GamefixId_COUNT]; public: GameDatabasePanel( wxWindow* parent ); diff --git a/pcsx2/gui/Panels/GameDatabasePanel.cpp b/pcsx2/gui/Panels/GameDatabasePanel.cpp index 301d7038e9..b278bce9cd 100644 --- a/pcsx2/gui/Panels/GameDatabasePanel.cpp +++ b/pcsx2/gui/Panels/GameDatabasePanel.cpp @@ -42,7 +42,10 @@ wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) : BaseApplicableConfigPanel( parent ) { - if (!GameDB) GameDB = new DataBase_Loader(); + //if (!GameDB) GameDB = new DataBase_Loader(); + DataBase_Loader* GameDB = AppHost_GetGameDatabase(); + pxAssume( GameDB != NULL ); + searchBtn = new wxButton (this, wxID_DEFAULT, L"Search"); serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); @@ -52,15 +55,8 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT); - gameFixes[0] = new pxCheckBox(this, L"VuAddSubHack"); - gameFixes[1] = new pxCheckBox(this, L"VuClipFlagHack"); - gameFixes[2] = new pxCheckBox(this, L"FpuCompareHack"); - gameFixes[3] = new pxCheckBox(this, L"FpuMulHack"); - gameFixes[4] = new pxCheckBox(this, L"FpuNegDivHack"); - gameFixes[5] = new pxCheckBox(this, L"XgKickHack"); - gameFixes[6] = new pxCheckBox(this, L"IPUWaitHack"); - gameFixes[7] = new pxCheckBox(this, L"EETimingHack"); - gameFixes[8] = new pxCheckBox(this, L"SkipMPEGHack"); + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + gameFixes[i] = new pxCheckBox(this, EnumToString(i)); *this += Heading(_("Game Database Editor")).Bold() | StdExpand(); *this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand(); @@ -84,14 +80,13 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) blankLine(); wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("PCSX2 Gamefixes")); - wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3)); + wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3, 0, StdPadding*4)); sizer3.AddGrowableCol(0); - for (int i = 0; i < NUM_OF_GAME_FIXES; i++) { + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) sizer3 += gameFixes[i]; - } - sizer2 += sizer3 | pxCenter; + sizer2 += sizer3 | StdCenter(); *this += sizer1 | pxCenter; *this += sizer2 | pxCenter; @@ -101,6 +96,8 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) } void Panels::GameDatabasePanel::PopulateFields() { + DataBase_Loader* GameDB = AppHost_GetGameDatabase(); + if (GameDB->gameLoaded()) { serialBox ->SetLabel(GameDB->getString("Serial")); nameBox ->SetLabel(GameDB->getString("Name")); @@ -108,15 +105,9 @@ void Panels::GameDatabasePanel::PopulateFields() { compatBox ->SetLabel(GameDB->getString("Compat")); commentBox->SetLabel(GameDB->getString("[comments]")); patchesBox->SetLabel(GameDB->getString("[patches]")); - gameFixes[0]->SetValue(GameDB->getBool("VuAddSubHack")); - gameFixes[1]->SetValue(GameDB->getBool("VuClipFlagHack")); - gameFixes[2]->SetValue(GameDB->getBool("FpuCompareHack")); - gameFixes[3]->SetValue(GameDB->getBool("FpuMulHack")); - gameFixes[4]->SetValue(GameDB->getBool("FpuNegDivHack")); - gameFixes[5]->SetValue(GameDB->getBool("XgKickHack")); - gameFixes[6]->SetValue(GameDB->getBool("IPUWaitHack")); - gameFixes[7]->SetValue(GameDB->getBool("EETimingHack")); - gameFixes[8]->SetValue(GameDB->getBool("SkipMPEGHack")); + + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + gameFixes[i]->SetValue(GameDB->getBool(EnumToString(i)+wxString(L"Hack"))); } else { serialBox ->SetLabel(L""); @@ -125,7 +116,7 @@ void Panels::GameDatabasePanel::PopulateFields() { compatBox ->SetLabel(L""); commentBox->SetLabel(L""); patchesBox->SetLabel(L""); - for (int i = 0; i < NUM_OF_GAME_FIXES; i++) { + for (int i = 0; i < GamefixId_COUNT; i++) { gameFixes[i]->SetValue(0); } } @@ -136,15 +127,11 @@ void Panels::GameDatabasePanel::PopulateFields() { else GameDB->writeString(wxT(_key), _value); \ } -#define writeGameFixToDB(_key, _value) { \ - if (!_value) GameDB->deleteKey(wxT(_key)); \ - else GameDB->writeBool(wxT(_key), _value); \ -} - // returns True if the database is modified, or FALSE if no changes to save. bool Panels::GameDatabasePanel::WriteFieldsToDB() { + DataBase_Loader* GameDB = AppHost_GetGameDatabase(); wxString wxStr( serialBox->GetValue() ); - + if (wxStr.IsEmpty()) return false; if (wxStr != GameDB->getString("Serial")) { GameDB->addGame(wxStr); @@ -155,19 +142,18 @@ bool Panels::GameDatabasePanel::WriteFieldsToDB() { writeTextBoxToDB("Compat", compatBox->GetValue()); writeTextBoxToDB("[comments]", commentBox->GetValue()); writeTextBoxToDB("[patches]", patchesBox->GetValue()); - writeGameFixToDB("VuAddSubHack", gameFixes[0]->GetValue()); - writeGameFixToDB("VuClipFlagHack", gameFixes[1]->GetValue()); - writeGameFixToDB("FpuCompareHack", gameFixes[2]->GetValue()); - writeGameFixToDB("FpuMulHack", gameFixes[3]->GetValue()); - writeGameFixToDB("FpuNegDivHack", gameFixes[4]->GetValue()); - writeGameFixToDB("XgKickHack", gameFixes[5]->GetValue()); - writeGameFixToDB("IPUWaitHack", gameFixes[6]->GetValue()); - writeGameFixToDB("EETimingHack", gameFixes[7]->GetValue()); - writeGameFixToDB("SkipMPEGHack", gameFixes[8]->GetValue()); + + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) { + const bool val = gameFixes[i]->GetValue(); + wxString keyName( EnumToString(i) ); keyName += L"Hack"; + if (!val) GameDB->deleteKey(keyName); + else GameDB->writeBool(keyName, val); + } return true; } void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) { + DataBase_Loader* GameDB = AppHost_GetGameDatabase(); wxString wxStr = serialBox->GetValue(); if( wxStr.IsEmpty() ) wxStr = DiscID; @@ -180,6 +166,7 @@ void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) { } void Panels::GameDatabasePanel::Apply() { + DataBase_Loader* GameDB = AppHost_GetGameDatabase(); if( WriteFieldsToDB() ) { Console.WriteLn("Saving changes to Game Database..."); diff --git a/pcsx2/gui/Panels/GameFixesPanel.cpp b/pcsx2/gui/Panels/GameFixesPanel.cpp index 78de290855..ab13168b46 100644 --- a/pcsx2/gui/Panels/GameFixesPanel.cpp +++ b/pcsx2/gui/Panels/GameFixesPanel.cpp @@ -31,7 +31,7 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) wxString label, tooltip; }; - const CheckTextMess check_text[NUM_OF_GAME_FIXES] = + const CheckTextMess check_text[GamefixId_COUNT] = { { _("VU Add Hack - Fixes Tri-Ace games boot crash."), @@ -71,12 +71,12 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) ) }, { - _("Skip MPEG hack - Skips videos/FMV's in games to avoid game hanging/freezes."), + _("Skip MPEG hack - Skips videos/FMVs in games to avoid game hanging/freezes."), wxEmptyString } }; - for( int i=0; iSetToolTip( check_text[i].tooltip ); @@ -102,31 +102,19 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) EnableStuff(); } -// I could still probably get rid of the for loop, but I think this is clearer. void Panels::GameFixesPanel::Apply() { g_Conf->EnableGameFixes = m_check_Enable->GetValue(); Pcsx2Config::GamefixOptions& opts( g_Conf->EmuOptions.Gamefixes ); - for (int i = 0; i < NUM_OF_GAME_FIXES; i++) - { - if (m_checkbox[i]->GetValue()) - { - opts.bitset |= (1 << i); - } - else - { - opts.bitset &= ~(1 << i); - } - } + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + opts.Set((GamefixId)i, m_checkbox[i]->GetValue()); } void Panels::GameFixesPanel::EnableStuff() { - for (int i = 0; i < NUM_OF_GAME_FIXES; i++) - { + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) m_checkbox[i]->Enable(m_check_Enable->GetValue()); - } } void Panels::GameFixesPanel::OnEnable_Toggled( wxCommandEvent& evt ) @@ -138,8 +126,6 @@ void Panels::GameFixesPanel::OnEnable_Toggled( wxCommandEvent& evt ) void Panels::GameFixesPanel::AppStatusEvent_OnSettingsApplied() { const Pcsx2Config::GamefixOptions& opts( g_Conf->EmuOptions.Gamefixes ); - for( int i=0; iSetValue( !!(opts.bitset & (1 << i)) ); - } + for (GamefixId i=GamefixId_FIRST; i < pxEnumEnd; ++i) + m_checkbox[i]->SetValue( opts.Get((GamefixId)i) ); }