diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index 7c099a1dce..8a38fff397 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -109,8 +109,8 @@ namespace Threading // derived class if your thread utilizes the post). // // Notes: - // * Constructing threads as static vars isn't recommended since it can potentially con- - // fuse w32pthreads, if the static initializers are executed out-of-order (C++ offers + // * Constructing threads as static global vars isn't recommended since it can potentially + // confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers // no dependency options for ensuring correct static var initializations). Use heap // allocation to create thread objects instead. // @@ -121,17 +121,19 @@ namespace Threading protected: typedef int (*PlainJoeFP)(); pthread_t m_thread; + Semaphore m_sem_event; // general wait event that's needed by most threads. sptr m_returncode; // value returned from the thread on close. - bool m_running; - Semaphore m_sem_event; // general wait event that's needed by most threads. - + volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid + volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc. + public: virtual ~PersistentThread(); PersistentThread(); virtual void Start(); virtual void Cancel( bool isBlocking = true ); + virtual void Detach(); // Gets the return code of the thread. // Throws std::logic_error if the thread has not terminated. @@ -142,6 +144,8 @@ namespace Threading bool IsSelf() const; + virtual void DoThreadCleanup(); + protected: // Used to dispatch the thread callback function. // (handles some thread cleanup on Win32, and is basically a typecast @@ -150,14 +154,6 @@ namespace Threading // Implemented by derived class to handle threading actions! virtual sptr ExecuteTask()=0; - - // ---------------------------------------------------------------------------- - // Static Methods (PersistentThread) - // ---------------------------------------------------------------------------- - public: - // performs a test on the given thread handle, returning true if the thread exists - // or false if the thread is dead/done/never existed. - static bool Exists( pthread_t pid ); }; ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index 43c0923ef1..80eef62e23 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -29,22 +29,40 @@ using namespace Threading; namespace Threading { + static void _pt_callback_cleanup( void* handle ) + { + ((PersistentThread*)handle)->DoThreadCleanup(); + } + PersistentThread::PersistentThread() : m_thread() - , m_returncode( 0 ) - , m_running( false ) , m_sem_event() + , m_returncode( 0 ) + , m_detached( false ) + , m_running( false ) { } - // Perform a blocking termination of the thread, to ensure full object cleanup. + // This destructor performs basic "last chance" cleanup, which is a blocking + // join against non-detached threads. Detached threads are unhandled. + // Extending classes should always implement their own thread closure process. + // This class must not be deleted from its own thread. That would be like marrying + // your sister, and then cheating on her with your daughter. PersistentThread::~PersistentThread() { - Cancel( false ); + wxASSERT( !IsSelf() ); // not allowed from our own thread. + + if( !_InterlockedExchange( &m_detached, true ) ) + { + pthread_join( m_thread, (void**)&m_returncode ); + m_running = false; + } } + // This function should not be called from the owner thread. void PersistentThread::Start() { + wxASSERT( !IsSelf() ); // not allowed from our own thread. if( m_running ) return; if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 ) @@ -53,26 +71,43 @@ namespace Threading m_running = true; } + // This function should not be called from the owner thread. + void PersistentThread::Detach() + { + wxASSERT( !IsSelf() ); // not allowed from our own thread. + if( _InterlockedExchange( &m_detached, true ) ) return; + pthread_detach( m_thread ); + } + // Remarks: // Provision of non-blocking Cancel() is probably academic, since destroying a PersistentThread // object performs a blocking Cancel regardless of if you explicitly do a non-blocking Cancel() // prior, since the ExecuteTask() method requires a valid object state. If you really need // fire-and-forget behavior on threads, use pthreads directly for now. - // (TODO : make a DetachedThread class?) + // + // This function should not be called from the owner thread. // // Parameters: // isBlocking - indicates if the Cancel action should block for thread completion or not. // void PersistentThread::Cancel( bool isBlocking ) { - if( !m_running ) return; - m_running = false; + wxASSERT( !IsSelf() ); + if( _InterlockedExchange( &m_detached, true ) ) + { + if( m_running ) + Console::Notice( "Threading Warning: Attempted to cancel detached thread; Ignoring..." ); + return; + } pthread_cancel( m_thread ); + if( isBlocking ) pthread_join( m_thread, (void**)&m_returncode ); else pthread_detach( m_thread ); + + m_running = false; } // Blocks execution of the calling thread until this thread completes its task. The @@ -85,11 +120,21 @@ namespace Threading // sptr PersistentThread::Block() { - bool isOwner = (pthread_self() == m_thread); - DevAssert( !isOwner, "Thread deadlock detected; Block() should never be called by the owner thread." ); + DevAssert( !IsSelf(), "Thread deadlock detected; Block() should never be called by the owner thread." ); + + if( _InterlockedExchange( &m_detached, true ) ) + { + // already detached: if we're still running then its an invalid operation + if( m_running ) + throw Exception::InvalidOperation( "Blocking on detached threads requires manual semaphore implementation." ); - pthread_join( m_thread, (void**)&m_returncode ); - return m_returncode; + return m_returncode; + } + else + { + pthread_join( m_thread, (void**)&m_returncode ); + return m_returncode; + } } bool PersistentThread::IsSelf() const @@ -97,15 +142,12 @@ namespace Threading return pthread_self() == m_thread; } - bool PersistentThread::Exists( pthread_t pid ) - { - // passing 0 to pthread_kill is a NOP, and returns the status of the thread only. - return ( ESRCH != pthread_kill( pid, 0 ) ); - } - bool PersistentThread::IsRunning() const { - return ( m_running && (ESRCH != pthread_kill( m_thread, 0 )) ); + if( !!m_detached ) + return !!m_running; + else + return ( ESRCH != pthread_kill( m_thread, 0 ) ); } // Exceptions: @@ -113,21 +155,28 @@ namespace Threading // sptr PersistentThread::GetReturnCode() const { - if( !m_running ) - throw Exception::InvalidOperation( "Thread.GetReturnCode : thread has not been started." ); - if( IsRunning() ) throw Exception::InvalidOperation( "Thread.GetReturnCode : thread is still running." ); return m_returncode; } + // invoked when canceling or exiting the thread. + void PersistentThread::DoThreadCleanup() + { + wxASSERT( IsSelf() ); // only allowed from our own thread, thanks. + _InterlockedExchange( &m_running, false ); + } + void* PersistentThread::_internal_callback( void* itsme ) { jASSUME( itsme != NULL ); - PersistentThread& owner = *((PersistentThread*)itsme); + + pthread_cleanup_push( _pt_callback_cleanup, itsme ); owner.m_returncode = owner.ExecuteTask(); + pthread_cleanup_pop( true ); + return (void*)owner.m_returncode; } diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 54bf053549..4db4f1cfdc 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -219,7 +219,7 @@ void mtgsThreadObject::Start() mtgsThreadObject::~mtgsThreadObject() { - Cancel(); + mtgsThreadObject::Cancel(); } void mtgsThreadObject::Cancel() diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index a1e5ab5121..e9fdb51e53 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -704,8 +704,9 @@ static bool OpenPlugin_GS() return true; } - if( mtgsThread->IsSelf() ) - return !GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 ); + if( !mtgsThread->IsSelf() ) return true; // already opened? + + return !GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 ); // Note: rederswitch is us abusing the isMultiThread parameter for that so // we don't need a new callback diff --git a/pcsx2/System.h b/pcsx2/System.h index c778acc454..08dd884fed 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -110,6 +110,6 @@ namespace Msgbox } BEGIN_DECLARE_EVENT_TYPES() - DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 ); - DECLARE_EVENT_TYPE( pxEVT_CallStackBox, -1 ); + DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 ) + DECLARE_EVENT_TYPE( pxEVT_CallStackBox, -1 ) END_DECLARE_EVENT_TYPES() diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index 68172d9239..7653f789e5 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -32,6 +32,89 @@ class IniInterface; +// ------------------------------------------------------------------------ +// All Menu Options for the Main Window! :D +// ------------------------------------------------------------------------ + +enum MenuIdentifiers +{ + // Main Menu Section + Menu_Run = 1, + Menu_Config, // General config, plus non audio/video plugins. + Menu_Video, // Video options filled in by GS plugin + Menu_Audio, // audio options filled in by SPU2 plugin + Menu_Misc, // Misc options and help! + + // Run SubSection + Menu_RunIso = 20, // Opens submenu with Iso browser, and recent isos. + Menu_IsoBrowse, // Open dialog, runs selected iso. + Menu_BootCDVD, // opens a submenu filled by CDVD plugin (usually list of drives) + Menu_RunWithoutDisc, // used to enter the bios (subs in cdvdnull) + Menu_RunELF, + Menu_SkipBiosToggle, // enables the Bios Skip speedhack + Menu_EnableSkipBios, // check marked menu that toggles Skip Bios boot feature. + Menu_PauseExec, // suspends/resumes active emulation + Menu_Reset, // Issues a complete reset. + Menu_States, // Opens states submenu + Menu_Run_Exit = wxID_EXIT, + + Menu_State_Load = 40, + Menu_State_LoadOther, + Menu_State_Load01, // first of many load slots + Menu_State_Save = 60, + Menu_State_SaveOther, + Menu_State_Save01, // first of many save slots + + // Config Subsection + Menu_Config_Settings = 100, + Menu_Config_BIOS, + Menu_Config_CDVD, + Menu_Config_DEV9, + Menu_Config_USB, + Menu_Config_FireWire, + Menu_Config_Patches, + + // Video Subsection + // Top items are Pcsx2-controlled. GS plugin items are inserted beneath. + Menu_Video_Basics = 200, // includes frame timings and skippings settings + Menu_Video_Advanced, // inserted at the bottom of the menu + Menu_GS_Custom1 = 210, // start index for GS custom entries (valid up to 299) + Menu_GS_CustomMax = 299, + + // Audio subsection + // Top items are Pcsx2-controlled. SPU2 plugin items are inserted beneath. + // [no items at this time] + Menu_Audio_Advanced = 300, // inserted at the bottom of the menu + Menu_Audio_Custom1 = 310, + Menu_Audio_CustomMax = 399, + + // Controller subsection + // Top items are Pcsx2-controlled. Pad plugin items are inserted beneath. + // [no items at this time] + Menu_Pad_Advanced = 400, + Menu_Pad_Custom1 = 410, + Menu_Pad_CustomMax = 499, + + // Miscellaneous Menu! (Misc) + Menu_About = wxID_ABOUT, + Menu_Website = 500, // Visit our awesome website! + Menu_Profiler, // Enable profiler + Menu_Console, // Enable console + Menu_Patches, + + // Debug Subsection + Menu_Debug_Open = 600, // opens the debugger window / starts a debug session + Menu_Debug_MemoryDump, + Menu_Debug_Logging, // dialog for selection additional log options + Menu_Debug_Usermode, + Menu_Languages, + + // Language Menu + // (Updated entirely dynamically, all values from range 1000 onward are reserved for languages) + Menu_Language_Start = 1000 +}; + + ////////////////////////////////////////////////////////////////////////////////////////// // struct AppImageIds @@ -97,7 +180,6 @@ class Pcsx2App : public wxApp protected: MainEmuFrame* m_MainFrame; ConsoleLogFrame* m_ProgramLogBox; - ConsoleLogFrame* m_Ps2ConLogBox; wxBitmap* m_Bitmap_Logo; wxImageList m_ConfigImages; @@ -135,16 +217,17 @@ public: return *m_MainFrame; } + void PostMenuAction( MenuIdentifiers menu_id ) const; + void Ping() const; + + // ---------------------------------------------------------------------------- + // Console / Program Logging Helpers + // ---------------------------------------------------------------------------- ConsoleLogFrame* GetProgramLog() { return m_ProgramLogBox; } - ConsoleLogFrame* GetConsoleLog() - { - return m_Ps2ConLogBox; - } - void CloseProgramLog() { m_ProgramLogBox->Close(); @@ -165,18 +248,13 @@ public: m_ProgramLogBox->GetEventHandler()->AddPendingEvent( evt ); } - void ConsoleLog_PostEvent( wxEvent& evt ) - { - if( m_Ps2ConLogBox == NULL ) return; - m_Ps2ConLogBox->GetEventHandler()->AddPendingEvent( evt ); - } - //ConsoleLogFrame* GetConsoleFrame() const { return m_ProgramLogBox; } //void SetConsoleFrame( ConsoleLogFrame& frame ) { m_ProgramLogBox = &frame; } protected: void ReadUserModeSettings(); bool TryOpenConfigCwd(); + void OnSemaphorePing( wxCommandEvent& evt ); void OnMessageBox( pxMessageBoxEvent& evt ); void CleanupMess(); void OpenWizardConsole(); diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 7c08078a37..ae1ca1193d 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -359,6 +359,7 @@ wxString AppConfig::FullpathToMcd( uint mcdidx ) const { return Path::Combine( F AppConfig::AppConfig() : MainGuiPosition( wxDefaultPosition ) +, SettingsTabName( L"Cpu" ) , LanguageId( wxLANGUAGE_DEFAULT ) , RecentFileCount( 6 ) , DeskTheme( L"default" ) @@ -418,6 +419,7 @@ void AppConfig::LoadSave( IniInterface& ini ) AppConfig defaults; IniEntry( MainGuiPosition ); + IniEntry( SettingsTabName ); ini.EnumEntry( L"LanguageId", LanguageId, NULL, defaults.LanguageId ); IniEntry( RecentFileCount ); IniEntry( DeskTheme ); diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index 8dd628fe3a..dae3f7299b 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -104,6 +104,10 @@ public: public: wxPoint MainGuiPosition; + // Because remembering the last used tab on the settings panel is cool (tab is remembered + // by it's UTF/ASCII name). + wxString SettingsTabName; + // Current language in use (correlates to a wxWidgets wxLANGUAGE specifier) wxLanguage LanguageId; diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index e3b0347db7..554f38cbb8 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -646,6 +646,9 @@ namespace Console { const wxString fmtline( wxString::FromAscii( fmt ) + L"\n" ); _immediate_logger( fmtline ); + + if( emuLog != NULL ) + fflush( emuLog ); // Implementation note: I've duplicated Write+Newline behavior here to avoid polluting // the message pump with lots of erroneous messages (Newlines can be bound into Write message). @@ -664,6 +667,9 @@ namespace Console const wxString fmtline( fmt + L"\n" ); _immediate_logger( fmtline ); + if( emuLog != NULL ) + fflush( emuLog ); + // Implementation note: I've duplicated Write+Newline behavior here to avoid polluting // the message pump with lots of erroneous messages (Newlines can be bound into Write message). diff --git a/pcsx2/gui/Dialogs/ConfigurationDialog.cpp b/pcsx2/gui/Dialogs/ConfigurationDialog.cpp index 22f8f187aa..d1f0368cfc 100644 --- a/pcsx2/gui/Dialogs/ConfigurationDialog.cpp +++ b/pcsx2/gui/Dialogs/ConfigurationDialog.cpp @@ -43,13 +43,22 @@ using namespace Panels; static const int s_orient = wxBK_LEFT; #endif +static const int IdealWidth = 500; + +template< typename T > +void Dialogs::ConfigurationDialog::AddPage( const char* label, int iconid ) +{ + const wxString labelstr( wxString::FromUTF8( label ) ); + const int curidx = m_labels.Add( labelstr ); + g_ApplyState.SetCurrentPage( curidx ); + m_listbook.AddPage( new T( m_listbook, IdealWidth ), wxGetTranslation( labelstr ), + ( labelstr == g_Conf->SettingsTabName ), iconid ); +} Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id ) : wxDialogWithHelpers( parent, id, _("PCSX2 Configuration"), true ) , m_listbook( *new wxListbook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, s_orient ) ) { - static const int IdealWidth = 500; - wxBoxSizer& mainSizer = *new wxBoxSizer( wxVERTICAL ); m_listbook.SetImageList( &wxGetApp().GetImgList_Config() ); @@ -57,24 +66,13 @@ Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id ) : g_ApplyState.StartBook( &m_listbook ); - g_ApplyState.SetCurrentPage( m_listbook.GetPageCount() ); - m_listbook.AddPage( new CpuPanel( m_listbook, IdealWidth ), _("CPU"), false, cfgid.Cpu ); - - g_ApplyState.SetCurrentPage( m_listbook.GetPageCount() ); - m_listbook.AddPage( new VideoPanel( m_listbook, IdealWidth ), _("GS/Video"), false, cfgid.Video ); - - g_ApplyState.SetCurrentPage( m_listbook.GetPageCount() ); - m_listbook.AddPage( new SpeedHacksPanel( m_listbook, IdealWidth ), _("Speedhacks"), false, cfgid.Speedhacks ); - - g_ApplyState.SetCurrentPage( m_listbook.GetPageCount() ); - m_listbook.AddPage( new GameFixesPanel( m_listbook, IdealWidth ), _("Game Fixes"), false, cfgid.Gamefixes ); - - g_ApplyState.SetCurrentPage( m_listbook.GetPageCount() ); - m_listbook.AddPage( new PluginSelectorPanel( m_listbook, IdealWidth ), _("Plugins"), false, cfgid.Plugins ); - - g_ApplyState.SetCurrentPage( m_listbook.GetPageCount() ); - m_listbook.AddPage( new StandardPathsPanel( m_listbook ), _("Folders"), false, cfgid.Paths ); - + AddPage ( wxLt("CPU"), cfgid.Cpu ); + AddPage ( wxLt("GS/Video"), cfgid.Video ); + AddPage ( wxLt("Speedhacks"), cfgid.Speedhacks ); + AddPage ( wxLt("Game Fixes"), cfgid.Gamefixes ); + AddPage( wxLt("Plugins"), cfgid.Plugins ); + AddPage ( wxLt("Folders"), cfgid.Paths ); + mainSizer.Add( &m_listbook ); AddOkCancel( mainSizer, true ); @@ -94,6 +92,7 @@ Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id ) : #endif Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnOk_Click ) ); + Connect( wxID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnCancel_Click ) ); Connect( wxID_APPLY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnApply_Click ) ); // ---------------------------------------------------------------------------- @@ -121,17 +120,30 @@ Dialogs::ConfigurationDialog::~ConfigurationDialog() void Dialogs::ConfigurationDialog::OnOk_Click( wxCommandEvent& evt ) { - if( g_ApplyState.ApplyAll() ) + if( g_ApplyState.ApplyAll( false ) ) { + FindWindow( wxID_APPLY )->Disable(); + g_Conf->SettingsTabName = m_labels[m_listbook.GetSelection()]; + g_Conf->Save(); + Close(); evt.Skip(); } } +void Dialogs::ConfigurationDialog::OnCancel_Click( wxCommandEvent& evt ) +{ + evt.Skip(); + g_Conf->SettingsTabName = m_labels[m_listbook.GetSelection()]; +} + void Dialogs::ConfigurationDialog::OnApply_Click( wxCommandEvent& evt ) { - FindWindow( wxID_APPLY )->Disable(); - g_ApplyState.ApplyAll(); + if( g_ApplyState.ApplyAll( false ) ) + FindWindow( wxID_APPLY )->Disable(); + + g_Conf->SettingsTabName = m_labels[m_listbook.GetSelection()]; + g_Conf->Save(); } diff --git a/pcsx2/gui/Dialogs/ConfigurationDialog.h b/pcsx2/gui/Dialogs/ConfigurationDialog.h index e119046fb4..893c1783b9 100644 --- a/pcsx2/gui/Dialogs/ConfigurationDialog.h +++ b/pcsx2/gui/Dialogs/ConfigurationDialog.h @@ -32,13 +32,18 @@ namespace Dialogs { protected: wxListbook& m_listbook; + wxArrayString m_labels; public: virtual ~ConfigurationDialog(); ConfigurationDialog(wxWindow* parent, int id=wxID_ANY); protected: + template< typename T > + void AddPage( const char* label, int iconid ); + void OnOk_Click( wxCommandEvent& evt ); + void OnCancel_Click( wxCommandEvent& evt ); void OnApply_Click( wxCommandEvent& evt ); virtual void OnSomethingChanged( wxCommandEvent& evt ) diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 332e858441..5b40893885 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -24,95 +24,12 @@ #include "App.h" -////////////////////////////////////////////////////////////////////////////////////////// -// class MainEmuFrame: public wxFrame { -protected: - // ------------------------------------------------------------------------ - // All Menu Options for the Main Window! :D - // ------------------------------------------------------------------------ - - enum Identifiers - { - // Main Menu Section - Menu_Run = 1, - Menu_Config, // General config, plus non audio/video plugins. - Menu_Video, // Video options filled in by GS plugin - Menu_Audio, // audio options filled in by SPU2 plugin - Menu_Misc, // Misc options and help! - - // Run SubSection - Menu_RunIso = 20, // Opens submenu with Iso browser, and recent isos. - Menu_IsoBrowse, // Open dialog, runs selected iso. - Menu_BootCDVD, // opens a submenu filled by CDVD plugin (usually list of drives) - Menu_RunWithoutDisc, // used to enter the bios (subs in cdvdnull) - Menu_RunELF, - Menu_SkipBiosToggle, // enables the Bios Skip speedhack - Menu_EnableSkipBios, // check marked menu that toggles Skip Bios boot feature. - Menu_PauseExec, // suspends/resumes active emulation - Menu_Reset, // Issues a complete reset. - Menu_States, // Opens states submenu - Menu_Run_Exit = wxID_EXIT, - - Menu_State_Load = 40, - Menu_State_LoadOther, - Menu_State_Load01, // first of many load slots - Menu_State_Save = 60, - Menu_State_SaveOther, - Menu_State_Save01, // first of many save slots - - // Config Subsection - Menu_Config_Settings = 100, - Menu_Config_BIOS, - Menu_Config_CDVD, - Menu_Config_DEV9, - Menu_Config_USB, - Menu_Config_FireWire, - Menu_Config_Patches, - - // Video Subsection - // Top items are Pcsx2-controlled. GS plugin items are inserted beneath. - Menu_Video_Basics = 200, // includes frame timings and skippings settings - Menu_Video_Advanced, // inserted at the bottom of the menu - Menu_GS_Custom1 = 210, // start index for GS custom entries (valid up to 299) - Menu_GS_CustomMax = 299, - - // Audio subsection - // Top items are Pcsx2-controlled. SPU2 plugin items are inserted beneath. - // [no items at this time] - Menu_Audio_Advanced = 300, // inserted at the bottom of the menu - Menu_Audio_Custom1 = 310, - Menu_Audio_CustomMax = 399, - - // Controller subsection - // Top items are Pcsx2-controlled. Pad plugin items are inserted beneath. - // [no items at this time] - Menu_Pad_Advanced = 400, - Menu_Pad_Custom1 = 410, - Menu_Pad_CustomMax = 499, - - // Miscellaneous Menu! (Misc) - Menu_About = wxID_ABOUT, - Menu_Website = 500, // Visit our awesome website! - Menu_Profiler, // Enable profiler - Menu_Console, // Enable console - Menu_Patches, - - // Debug Subsection - Menu_Debug_Open = 600, // opens the debugger window / starts a debug session - Menu_Debug_MemoryDump, - Menu_Debug_Logging, // dialog for selection additional log options - Menu_Debug_Usermode, - Menu_Languages, - - // Language Menu - // (Updated entirely dynamically, all values from range 1000 onward are reserved for languages) - Menu_Language_Start = 1000 - }; +public: // ------------------------------------------------------------------------ - // MainEmuFrame Protected Variables + // MainEmuFrame Protected Variables // ------------------------------------------------------------------------ protected: @@ -138,7 +55,7 @@ protected: bool m_IsPaused; // ------------------------------------------------------------------------ - // MainEmuFrame Constructors and Member Methods + // MainEmuFrame Constructors and Member Methods // ------------------------------------------------------------------------ public: @@ -177,7 +94,7 @@ protected: void Menu_ShowAboutBox(wxCommandEvent &event); // ------------------------------------------------------------------------ - // MainEmuFram Internal API for Populating Main Menu Contents + // MainEmuFram Internal API for Populating Main Menu Contents // ------------------------------------------------------------------------ wxMenu* MakeStatesSubMenu( int baseid ) const; diff --git a/pcsx2/gui/Panels/ConfigurationPanels.h b/pcsx2/gui/Panels/ConfigurationPanels.h index a1a689087c..f97684fbd5 100644 --- a/pcsx2/gui/Panels/ConfigurationPanels.h +++ b/pcsx2/gui/Panels/ConfigurationPanels.h @@ -118,7 +118,7 @@ namespace Panels void StartBook( wxBookCtrlBase* book ); void StartWizard(); - bool ApplyAll(); + bool ApplyAll( bool saveOnSuccess=true ); bool ApplyPage( int pageid, bool saveOnSuccess=true ); void DoCleanup(); }; @@ -323,7 +323,7 @@ namespace Panels class StandardPathsPanel : public BasePathsPanel { public: - StandardPathsPanel( wxWindow& parent ); + StandardPathsPanel( wxWindow& parent, int idealWidth ); }; ////////////////////////////////////////////////////////////////////////////////////////// @@ -452,8 +452,8 @@ namespace Panels public: virtual ~PluginSelectorPanel(); PluginSelectorPanel( wxWindow& parent, int idealWidth ); - virtual void CancelRefresh(); + void CancelRefresh(); // used from destructor, stays non-virtual void Apply( AppConfig& conf ); protected: diff --git a/pcsx2/gui/Panels/DirPickerPanel.cpp b/pcsx2/gui/Panels/DirPickerPanel.cpp index edb369acd4..8045dab013 100644 --- a/pcsx2/gui/Panels/DirPickerPanel.cpp +++ b/pcsx2/gui/Panels/DirPickerPanel.cpp @@ -33,7 +33,7 @@ static wxString GetNormalizedConfigFolder( FoldersEnum_t folderId ) return normalized.ToString(); } -// Pass me TRUE if the default path is to be used, and the DirPcikerCtrl disabled from use. +// Pass me TRUE if the default path is to be used, and the DirPickerCtrl disabled from use. void Panels::DirPickerPanel::UpdateCheckStatus( bool someNoteworthyBoolean ) { m_pickerCtrl->Enable( !someNoteworthyBoolean ); diff --git a/pcsx2/gui/Panels/MiscPanelStuff.cpp b/pcsx2/gui/Panels/MiscPanelStuff.cpp index 7f1a137f19..e0b0e9da3a 100644 --- a/pcsx2/gui/Panels/MiscPanelStuff.cpp +++ b/pcsx2/gui/Panels/MiscPanelStuff.cpp @@ -100,9 +100,9 @@ bool Panels::StaticApplyState::ApplyPage( int pageid, bool saveOnSuccess ) // Returns false if one of the panels fails input validation (in which case dialogs // should not be closed, etc). -bool Panels::StaticApplyState::ApplyAll() +bool Panels::StaticApplyState::ApplyAll( bool saveOnSuccess ) { - return ApplyPage( -1 ); + return ApplyPage( -1, saveOnSuccess ); } // ----------------------------------------------------------------------- diff --git a/pcsx2/gui/Panels/PathsPanel.cpp b/pcsx2/gui/Panels/PathsPanel.cpp index ce85e4c1fa..72a165af09 100644 --- a/pcsx2/gui/Panels/PathsPanel.cpp +++ b/pcsx2/gui/Panels/PathsPanel.cpp @@ -40,7 +40,7 @@ Panels::DirPickerPanel& Panels::BasePathsPanel::AddDirPicker( wxBoxSizer& sizer, } // ------------------------------------------------------------------------ -Panels::StandardPathsPanel::StandardPathsPanel( wxWindow& parent ) : +Panels::StandardPathsPanel::StandardPathsPanel( wxWindow& parent, __unused int idealWidth ) : BasePathsPanel( parent ) { s_main.AddSpacer( BetweenFolderSpace ); diff --git a/pcsx2/gui/Panels/PluginSelectorPanel.cpp b/pcsx2/gui/Panels/PluginSelectorPanel.cpp index 94dd471f19..92c0d399a4 100644 --- a/pcsx2/gui/Panels/PluginSelectorPanel.cpp +++ b/pcsx2/gui/Panels/PluginSelectorPanel.cpp @@ -420,7 +420,7 @@ Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master Panels::PluginSelectorPanel::EnumThread::~EnumThread() { - Cancel(); + EnumThread::Cancel(); safe_delete_array( Results ); } @@ -435,7 +435,7 @@ sptr Panels::PluginSelectorPanel::EnumThread::ExecuteTask() { DevCon::Status( "Plugin Enumeration Thread started..." ); - Sleep( 10 ); // gives the gui thread some time to refresh + wxGetApp().Ping(); // gives the gui thread some time to refresh for( int curidx=0; curidx < m_master.FileCount(); ++curidx ) { diff --git a/pcsx2/gui/main.cpp b/pcsx2/gui/main.cpp index c8a40c4e4e..c8c51b31bf 100644 --- a/pcsx2/gui/main.cpp +++ b/pcsx2/gui/main.cpp @@ -31,6 +31,12 @@ IMPLEMENT_APP(Pcsx2App) +DEFINE_EVENT_TYPE( pxEVT_SemaphorePing ) + +BEGIN_DECLARE_EVENT_TYPES() + DECLARE_EVENT_TYPE( pxEVT_SemaphorePing, -1 ) +END_DECLARE_EVENT_TYPES() + bool UseAdminMode = false; AppConfig* g_Conf = NULL; wxFileHistory* g_RecentIsoList = NULL; @@ -77,8 +83,15 @@ sptr AppEmuThread::ExecuteTask() { if( ex.StreamName == g_Conf->FullpathToBios() ) { - Msgbox::OkCancel( ex.FormatDisplayMessage() + + GetPluginManager().Close(); + bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() + _("\n\nPress Ok to go to the BIOS Configuration Panel.") ); + + if( result ) + { + wxGetApp().PostMenuAction( Menu_Config_BIOS ); + wxGetApp().Ping(); + } } else { @@ -91,16 +104,17 @@ sptr AppEmuThread::ExecuteTask() if( g_Conf->FullpathTo( pid ) == ex.StreamName ) break; } - if( pi->shortname == NULL ) - { - // Some other crap file failure >_< - } - - int result = Msgbox::OkCancel( ex.FormatDisplayMessage() + - _("\n\nPress Ok to go to the Plugin Configuration Panel.") ); - - if( result == wxID_OK ) + if( pi->shortname != NULL ) { + bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() + + _("\n\nPress Ok to go to the Plugin Configuration Panel.") ); + + if( result ) + { + g_Conf->SettingsTabName = L"Plugins"; + wxGetApp().PostMenuAction( Menu_Config_Settings ); + wxGetApp().Ping(); + } } } } @@ -163,6 +177,7 @@ void Pcsx2App::ReadUserModeSettings() // Save user's new settings IniSaver saver( *conf_usermode ); g_Conf->LoadSaveUserMode( saver, groupname ); + AppConfig_ReloadGlobalSettings( true ); g_Conf->Save(); } else @@ -187,6 +202,7 @@ void Pcsx2App::ReadUserModeSettings() // Save user's new settings IniSaver saver( *conf_usermode ); g_Conf->LoadSaveUserMode( saver, groupname ); + AppConfig_ReloadGlobalSettings( true ); g_Conf->Save(); } } @@ -242,6 +258,13 @@ bool Pcsx2App::OnInit() wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() ); +#define pxMessageBoxEventThing(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxMessageBoxEventFunction, &func ) + + Connect( pxEVT_MSGBOX, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) ); + Connect( pxEVT_CallStackBox, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) ); + Connect( pxEVT_SemaphorePing, wxCommandEventHandler( Pcsx2App::OnSemaphorePing ) ); + // User/Admin Mode Dual Setup: // Pcsx2 now supports two fundamental modes of operation. The default is Classic mode, // which uses the Current Working Directory (CWD) for all user data files, and requires @@ -270,9 +293,6 @@ bool Pcsx2App::OnInit() m_ProgramLogBox = new ConsoleLogFrame( m_MainFrame, L"PCSX2 Program Log", g_Conf->ProgLogBox ); - m_Ps2ConLogBox = m_ProgramLogBox; // just use a single logger for now. - //m_Ps2ConLogBox = new ConsoleLogFrame( NULL, L"PS2 Console Log" ); - SetTopWindow( m_MainFrame ); // not really needed... SetExitOnFrameDelete( true ); // but being explicit doesn't hurt... m_MainFrame->Show(); @@ -286,15 +306,42 @@ bool Pcsx2App::OnInit() return false; } - #define pxMessageBoxEventThing(func) \ - (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxMessageBoxEventFunction, &func ) - - Connect( pxEVT_MSGBOX, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) ); - Connect( pxEVT_CallStackBox,pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) ); - return true; } +// Allows for activating menu actions from anywhere in PCSX2. +// And it's Thread Safe! +void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const +{ + wxASSERT( m_MainFrame != NULL ); + if( m_MainFrame == NULL ) return; + + wxCommandEvent joe( wxEVT_COMMAND_MENU_SELECTED, menu_id ); + m_MainFrame->GetEventHandler()->AddPendingEvent( joe ); +} + +// Waits for the main GUI thread to respond. If run from the main GUI thread, returns +// immediately without error. +void Pcsx2App::Ping() const +{ + if( wxThread::IsMain() ) return; + + Semaphore sema; + wxCommandEvent bean( pxEVT_SemaphorePing ); + bean.SetClientData( &sema ); + wxGetApp().AddPendingEvent( bean ); + sema.WaitNoCancel(); +} + +// ---------------------------------------------------------------------------- +// Pcsx2App Event Handlers +// ---------------------------------------------------------------------------- + +void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt ) +{ + ((Semaphore*)evt.GetClientData())->Post(); +} + void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt ) { Msgbox::OnEvent( evt ); @@ -351,7 +398,6 @@ int Pcsx2App::OnExit() Pcsx2App::Pcsx2App() : m_ProgramLogBox( NULL ) -, m_Ps2ConLogBox( NULL ) , m_ConfigImages( 32, 32 ) , m_ConfigImagesAreLoaded( false ) , m_ToolbarImages( NULL ) diff --git a/pcsx2/ps2/CoreEmuThread.cpp b/pcsx2/ps2/CoreEmuThread.cpp index 2fd341a318..e966a11b8a 100644 --- a/pcsx2/ps2/CoreEmuThread.cpp +++ b/pcsx2/ps2/CoreEmuThread.cpp @@ -103,11 +103,9 @@ sptr CoreEmuThread::ExecuteTask() m_ResumeEvent.Wait(); } - pthread_cleanup_push( _cet_callback_cleanup, this ); CpuInitializeMess(); StateCheck(); CpuExecute(); - pthread_cleanup_pop( true ); return 0; } @@ -154,20 +152,17 @@ CoreEmuThread::CoreEmuThread( const wxString& elf_file ) : , m_lock_ExecMode() { PersistentThread::Start(); - pthread_detach( m_thread ); } // Invoked by the pthread_exit or pthread_cancel void CoreEmuThread::DoThreadCleanup() { - wxASSERT( IsSelf() ); // only allowed from our own thread, thanks. - m_running = false; + PersistentThread::DoThreadCleanup(); GetPluginManager().Close(); } CoreEmuThread::~CoreEmuThread() { - Cancel(); } // Resumes the core execution state, or does nothing is the core is already running. If