From ac1df9667855f7c71919b33e125fe57a9a6c2892 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Fri, 8 Jan 2010 07:11:33 +0000 Subject: [PATCH] * Hopeful fix for DX10 memory leaks. * Likely fix for various plugin configuration button hangs/crashes. * Worked on the new GS window text label stuff a bit more (still needs more tho) Devel Note: * Lots of code cleanups regarding app message handling * Added wxAppWithHelpers.cpp/h files (linux projects need updated but too tired.. >_<) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2411 96395faa-99c1-11dd-bbfe-3dabce05a288 --- 3rdparty/wxWidgets/include/wx/event.h | 8 +- 3rdparty/wxWidgets/src/common/event.cpp | 8 +- pcsx2/GS.h | 4 +- pcsx2/MTGS.cpp | 1 + pcsx2/PluginManager.cpp | 74 +++-- pcsx2/Plugins.h | 43 ++- pcsx2/RecoverySystem.cpp | 6 +- pcsx2/System.h | 9 - pcsx2/System/SysThreadBase.cpp | 1 + pcsx2/gui/App.h | 91 ++---- pcsx2/gui/AppCommon.h | 8 +- pcsx2/gui/AppCoreThread.cpp | 31 +- pcsx2/gui/AppInit.cpp | 41 +-- pcsx2/gui/AppMain.cpp | 162 ++++++---- pcsx2/gui/Dialogs/ModalPopups.h | 88 ------ pcsx2/gui/FrameForGS.cpp | 57 ++-- pcsx2/gui/IniInterface.cpp | 2 +- pcsx2/gui/IniInterface.h | 2 +- pcsx2/gui/MainFrame.h | 4 + pcsx2/gui/MainMenuClicks.cpp | 10 +- pcsx2/gui/MessageBoxes.cpp | 342 +++++++++------------ pcsx2/gui/Plugins.cpp | 89 ++++-- pcsx2/gui/wxAppWithHelpers.cpp | 149 +++++++++ pcsx2/gui/wxAppWithHelpers.h | 302 ++++++++++++++++++ pcsx2/windows/VCprojects/pcsx2_2008.vcproj | 8 + 25 files changed, 951 insertions(+), 589 deletions(-) create mode 100644 pcsx2/gui/wxAppWithHelpers.cpp create mode 100644 pcsx2/gui/wxAppWithHelpers.h diff --git a/3rdparty/wxWidgets/include/wx/event.h b/3rdparty/wxWidgets/include/wx/event.h index 26fab62c9f..67a6c09439 100644 --- a/3rdparty/wxWidgets/include/wx/event.h +++ b/3rdparty/wxWidgets/include/wx/event.h @@ -260,7 +260,7 @@ BEGIN_DECLARE_EVENT_TYPES() DECLARE_EVENT_TYPE(wxEVT_MEASURE_ITEM, 436) DECLARE_EVENT_TYPE(wxEVT_COMPARE_ITEM, 437) DECLARE_EVENT_TYPE(wxEVT_INIT_DIALOG, 438) - DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_BASE, wxEVT_IDLE, 439) + DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_BASE, wxEvt_Idle, 439) DECLARE_EVENT_TYPE(wxEVT_UPDATE_UI, 440) DECLARE_EVENT_TYPE(wxEVT_SIZING, 441) DECLARE_EVENT_TYPE(wxEVT_MOVING, 442) @@ -2127,7 +2127,7 @@ private: // Idle event /* - wxEVT_IDLE + wxEvt_Idle */ // Whether to always send idle events to windows, or @@ -2148,7 +2148,7 @@ class WXDLLIMPEXP_CORE wxIdleEvent : public wxEvent { public: wxIdleEvent() - : wxEvent(0, wxEVT_IDLE), + : wxEvent(0, wxEvt_Idle), m_requestMore(false) { } wxIdleEvent(const wxIdleEvent & event) @@ -3069,7 +3069,7 @@ typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent& EVT_JOY_ZMOVE(func) // Idle event -#define EVT_IDLE(func) wx__DECLARE_EVT0(wxEVT_IDLE, wxIdleEventHandler(func)) +#define EVT_IDLE(func) wx__DECLARE_EVT0(wxEvt_Idle, wxIdleEventHandler(func)) // Update UI event #define EVT_UPDATE_UI(winid, func) wx__DECLARE_EVT1(wxEVT_UPDATE_UI, winid, wxUpdateUIEventHandler(func)) diff --git a/3rdparty/wxWidgets/src/common/event.cpp b/3rdparty/wxWidgets/src/common/event.cpp index d6518ce9c6..9f1ca27fe3 100644 --- a/3rdparty/wxWidgets/src/common/event.cpp +++ b/3rdparty/wxWidgets/src/common/event.cpp @@ -157,7 +157,7 @@ const wxEventType wxEVT_FIRST = 10000; const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000; DEFINE_EVENT_TYPE(wxEVT_NULL) -DEFINE_EVENT_TYPE(wxEVT_IDLE) +DEFINE_EVENT_TYPE(wxEvt_Idle) DEFINE_EVENT_TYPE(wxEVT_SOCKET) #endif // !WXWIN_COMPATIBILITY_EVENT_TYPES @@ -1248,10 +1248,10 @@ bool wxEvtHandler::TryParent(wxEvent& event) { if ( wxTheApp && (this != wxTheApp) ) { - // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always - // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be + // Special case: don't pass wxEvt_Idle to wxApp, since it'll always + // swallow it. wxEvt_Idle is sent explicitly to wxApp so it will be // processed appropriately via SearchEventTable. - if ( event.GetEventType() != wxEVT_IDLE ) + if ( event.GetEventType() != wxEvt_Idle ) { if ( wxTheApp->ProcessEvent(event) ) return true; diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 8443d2ecdc..d8bcb8daf3 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -247,8 +247,6 @@ public: SysMtgsThread(); virtual ~SysMtgsThread() throw(); - static SysMtgsThread& Get(); - // Waits for the GS to empty out the entire ring buffer contents. // Used primarily for plugin startup/shutdown. void WaitGS(); @@ -269,6 +267,8 @@ public: void SetEvent(); void PostVsyncEnd(); + bool IsPluginOpened() const { return m_PluginOpened; } + protected: void OpenPlugin(); void ClosePlugin(); diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 2f4bee1a05..5ab38c52ad 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -998,6 +998,7 @@ void SysMtgsThread::WaitForOpen() void SysMtgsThread::Freeze( int mode, MTGS_FreezeData& data ) { + GetPluginManager().Open( PluginId_GS ); SendPointerPacket( GS_RINGTYPE_FREEZE, mode, &data ); Resume(); WaitGS(); diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index b38d753e9f..270637a56d 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -875,18 +875,23 @@ extern void spu2DMA4Irq(); extern void spu2DMA7Irq(); extern void spu2Irq(); -static bool OpenPlugin_GS() +bool PluginManager::OpenPlugin_CDVD() +{ + return DoCDVDopen(); +} + +bool PluginManager::OpenPlugin_GS() { GetMTGS().Resume(); return true; } -static bool OpenPlugin_PAD() +bool PluginManager::OpenPlugin_PAD() { return !PADopen( (void*)&pDsp ); } -static bool OpenPlugin_SPU2() +bool PluginManager::OpenPlugin_SPU2() { if( SPU2open((void*)&pDsp) ) return false; @@ -896,7 +901,7 @@ static bool OpenPlugin_SPU2() return true; } -static bool OpenPlugin_DEV9() +bool PluginManager::OpenPlugin_DEV9() { dev9Handler = NULL; @@ -906,7 +911,7 @@ static bool OpenPlugin_DEV9() return true; } -static bool OpenPlugin_USB() +bool PluginManager::OpenPlugin_USB() { usbHandler = NULL; @@ -918,7 +923,7 @@ static bool OpenPlugin_USB() return true; } -static bool OpenPlugin_FW() +bool PluginManager::OpenPlugin_FW() { if( FWopen((void*)&pDsp) ) return false; FWirqCallback( fwIrq ); @@ -936,7 +941,7 @@ void PluginManager::Open( PluginsEnum_t pid ) bool result = true; switch( pid ) { - case PluginId_CDVD: result = DoCDVDopen(); break; + case PluginId_CDVD: result = OpenPlugin_CDVD(); break; case PluginId_GS: result = OpenPlugin_GS(); break; case PluginId_PAD: result = OpenPlugin_PAD(); break; case PluginId_SPU2: result = OpenPlugin_SPU2(); break; @@ -951,21 +956,33 @@ void PluginManager::Open( PluginsEnum_t pid ) m_info[pid].IsOpened = true; } -void PluginManager::Open() +bool PluginManager::NeedsOpen() const { - // Spam stopper: If all plugins are already opened, then return before writing any logs. >_< - const PluginInfo* pi = tbl_PluginInfo; do { if( !m_info[pi->id].IsOpened ) break; } while( ++pi, pi->shortname != NULL ); - if( pi->shortname == NULL ) return; + return pi->shortname != NULL; +} + +bool PluginManager::NeedsClose() const +{ + const PluginInfo* pi = tbl_PluginInfo; do { + if( m_info[pi->id].IsOpened ) break; + } while( ++pi, pi->shortname != NULL ); + + return pi->shortname != NULL; +} + +void PluginManager::Open() +{ + if( !NeedsOpen() ) return; // Spam stopper: returns before writing any logs. >_< Console.WriteLn( Color_StrongBlue, "Opening plugins..." ); SendSettingsFolder(); - pi = tbl_PluginInfo; do { + const PluginInfo* pi = tbl_PluginInfo; do { Open( pi->id ); // If GS doesn't support GSopen2, need to wait until call to GSopen // returns to populate pDsp. If it does, can initialize other plugins @@ -978,17 +995,21 @@ void PluginManager::Open() Console.WriteLn( Color_StrongBlue, "Plugins opened successfully." ); } +void PluginManager::ClosePlugin_GS() +{ + // force-close PAD before GS, because the PAD depends on the GS window. + + Close( PluginId_PAD ); + GetMTGS().Suspend(); +} + void PluginManager::Close( PluginsEnum_t pid ) { if( !m_info[pid].IsOpened ) return; Console.Indent().WriteLn( "Closing %s", tbl_PluginInfo[pid].shortname ); if( pid == PluginId_GS ) - { - // force-close PAD before GS, because the PAD depends on the GS window. - Close( PluginId_PAD ); - GetMTGS().Suspend(); - } + ClosePlugin_GS(); else if( pid == PluginId_CDVD ) DoCDVDclose(); else @@ -997,25 +1018,16 @@ void PluginManager::Close( PluginsEnum_t pid ) m_info[pid].IsOpened = false; } -void PluginManager::Close( bool closegs ) +void PluginManager::Close() { - // Spam stopper: If all plugins are already closed, then return before writing any logs. >_< - - const PluginInfo* pi = tbl_PluginInfo; do { - if( m_info[pi->id].IsOpened && (closegs || (pi->id != PluginId_GS)) ) break; - } while( ++pi, pi->shortname != NULL ); - - if( pi->shortname == NULL ) return; - - DbgCon.WriteLn( Color_StrongBlue, "Closing plugins..." ); + if( !NeedsClose() ) return; // Spam stopper; returns before writing any logs. >_< // Close plugins in reverse order of the initialization procedure. + DbgCon.WriteLn( Color_StrongBlue, "Closing plugins..." ); + for( int i=PluginId_Count-1; i>=0; --i ) - { - if( closegs || (tbl_PluginInfo[i].id != PluginId_GS) ) - Close( tbl_PluginInfo[i].id ); - } + Close( tbl_PluginInfo[i].id ); DbgCon.WriteLn( Color_StrongBlue, "Plugins closed successfully." ); } diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 71062d2b6c..abf82a021c 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -248,7 +248,9 @@ public: virtual void Open() { } virtual void Open( PluginsEnum_t pid ) { pxFail( "Null PluginManager!" ); } virtual void Close( PluginsEnum_t pid ) {} - virtual void Close( bool closegs=true ) {} + virtual void Close() {} + + virtual bool IsOpen( PluginsEnum_t pid ) const { return false; } virtual void Freeze( PluginsEnum_t pid, SaveStateBase& state ) { pxFail( "Null PluginManager!" ); } virtual bool DoFreeze( PluginsEnum_t pid, int mode, freezeData* data ) @@ -298,20 +300,25 @@ public: PluginManager( const wxString (&folders)[PluginId_Count] ); virtual ~PluginManager() throw(); - void Init(); - void Shutdown(); - void Open(); - void Open( PluginsEnum_t pid ); - void Close( PluginsEnum_t pid ); - void Close( bool closegs=true ); + virtual void Init(); + virtual void Shutdown(); + virtual void Open(); + virtual void Open( PluginsEnum_t pid ); + virtual void Close( PluginsEnum_t pid ); + virtual void Close(); - void Freeze( PluginsEnum_t pid, SaveStateBase& state ); - bool DoFreeze( PluginsEnum_t pid, int mode, freezeData* data ); + virtual bool IsOpen( PluginsEnum_t pid ) const { return m_info[pid].IsOpened; } + + virtual bool NeedsClose() const; + virtual bool NeedsOpen() const; + + virtual void Freeze( PluginsEnum_t pid, SaveStateBase& state ); + virtual bool DoFreeze( PluginsEnum_t pid, int mode, freezeData* data ); - bool KeyEvent( const keyEvent& evt ); - void Configure( PluginsEnum_t pid ); - void SetSettingsFolder( const wxString& folder ); - void SendSettingsFolder(); + virtual bool KeyEvent( const keyEvent& evt ); + virtual void Configure( PluginsEnum_t pid ); + virtual void SetSettingsFolder( const wxString& folder ); + virtual void SendSettingsFolder(); const wxString& GetName( PluginsEnum_t pid ) const { return m_info[pid].Name; } const wxString& GetVersion( PluginsEnum_t pid ) const { return m_info[pid].Version; } @@ -322,6 +329,16 @@ protected: void BindCommon( PluginsEnum_t pid ); void BindRequired( PluginsEnum_t pid ); void BindOptional( PluginsEnum_t pid ); + + virtual bool OpenPlugin_GS(); + virtual bool OpenPlugin_CDVD(); + virtual bool OpenPlugin_PAD(); + virtual bool OpenPlugin_SPU2(); + virtual bool OpenPlugin_DEV9(); + virtual bool OpenPlugin_USB(); + virtual bool OpenPlugin_FW(); + + virtual void ClosePlugin_GS(); friend class SysMtgsThread; }; diff --git a/pcsx2/RecoverySystem.cpp b/pcsx2/RecoverySystem.cpp index 32e781061c..1a5834e5be 100644 --- a/pcsx2/RecoverySystem.cpp +++ b/pcsx2/RecoverySystem.cpp @@ -107,11 +107,7 @@ protected: void SendFinishEvent( int type ) { - wxCommandEvent evt( pxEVT_FreezeThreadFinished ); - evt.SetClientData( this ); - evt.SetInt( type ); - evt.SetExtraLong( m_resume_when_done ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().PostCommand( this, pxEvt_FreezeThreadFinished, type, m_resume_when_done ); } }; diff --git a/pcsx2/System.h b/pcsx2/System.h index b151375433..37a223d9e4 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -105,13 +105,8 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true ); // responded to the prompt. // -class pxMessageBoxEvent; -class pxAssertionEvent; - namespace Msgbox { - extern void OnEvent( pxMessageBoxEvent& evt ); - extern bool Alert( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_EXCLAMATION ); extern bool OkCancel( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=0 ); extern bool YesNo( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_QUESTION ); @@ -119,7 +114,3 @@ namespace Msgbox extern int Assertion( const wxString& text, const wxString& stacktrace ); } -BEGIN_DECLARE_EVENT_TYPES() - DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 ) - DECLARE_EVENT_TYPE( pxEVT_ASSERTION, -1 ) -END_DECLARE_EVENT_TYPES() diff --git a/pcsx2/System/SysThreadBase.cpp b/pcsx2/System/SysThreadBase.cpp index 27497fd8f9..160bfaed5a 100644 --- a/pcsx2/System/SysThreadBase.cpp +++ b/pcsx2/System/SysThreadBase.cpp @@ -97,6 +97,7 @@ bool SysThreadBase::Suspend( bool isBlocking ) case ExecMode_Pausing: case ExecMode_Paused: + if( !isBlocking ) return retval; throw Exception::CancelEvent( "Another thread is pausing the VM state." ); case ExecMode_Opened: diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index 081e088de7..45913abe3d 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -15,32 +15,37 @@ #pragma once -#include +#include "wxAppWithHelpers.h" + #include #include #include -#include "IniInterface.h" - -#include "Utilities/HashMap.h" - #include "AppCommon.h" #include "RecentIsoList.h" #include "System.h" #include "System/SysThreads.h" +#include "Utilities/HashMap.h" + +class Pcsx2App; + typedef void FnType_OnThreadComplete(const wxCommandEvent& evt); +typedef void (Pcsx2App::*FnType_AppMethod)(); BEGIN_DECLARE_EVENT_TYPES() - DECLARE_EVENT_TYPE( pxEVT_OpenModalDialog, -1 ) - DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 ) - DECLARE_EVENT_TYPE( pxEVT_SysExecute, -1 ) - DECLARE_EVENT_TYPE( pxEVT_LoadPluginsComplete, -1 ) - DECLARE_EVENT_TYPE( pxEVT_CoreThreadStatus, -1 ) - DECLARE_EVENT_TYPE( pxEVT_FreezeThreadFinished, -1 ) - DECLARE_EVENT_TYPE( pxEVT_Ping, -1 ) - DECLARE_EVENT_TYPE( pxEVT_LogicalVsync, -1 ) + /*DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 ) + DECLARE_EVENT_TYPE( pxEVT_OpenGsPanel, -1 )*/ + + DECLARE_EVENT_TYPE( pxEvt_FreezeThreadFinished, -1 ) + DECLARE_EVENT_TYPE( pxEvt_CoreThreadStatus, -1 ) + DECLARE_EVENT_TYPE( pxEvt_LoadPluginsComplete, -1 ) + DECLARE_EVENT_TYPE( pxEvt_PluginStatus, -1 ) + DECLARE_EVENT_TYPE( pxEvt_SysExecute, -1 ) + DECLARE_EVENT_TYPE( pxEvt_OpenModalDialog, -1 ) + DECLARE_EVENT_TYPE( pxEvt_InvokeMethod, -1 ) + DECLARE_EVENT_TYPE( pxEvt_LogicalVsync, -1 ) END_DECLARE_EVENT_TYPES() // This is used when the GS plugin is handling its own window. Messages from the PAD @@ -297,39 +302,13 @@ struct pxAppResources ~pxAppResources() throw() { } }; -struct MsgboxEventResult -{ - Semaphore WaitForMe; - int result; - - MsgboxEventResult() - { - result = 0; - } -}; - -// -------------------------------------------------------------------------------------- -// AppIniSaver / AppIniLoader -// -------------------------------------------------------------------------------------- -class AppIniSaver : public IniSaver -{ -public: - AppIniSaver(); - virtual ~AppIniSaver() {} -}; - -class AppIniLoader : public IniLoader -{ -public: - AppIniLoader(); - virtual ~AppIniLoader() {} -}; - // ===================================================================================================== // Pcsx2App - main wxApp class // ===================================================================================================== -class Pcsx2App : public wxApp +class Pcsx2App : public wxAppWithHelpers { + typedef wxAppWithHelpers _parent; + // ---------------------------------------------------------------------------- // Event Sources! // These need to be at the top of the App class, because a lot of other things depend @@ -343,11 +322,11 @@ protected: EventSource m_evtsrc_AppStatus; public: - CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; } - EventSource& Source_SettingsApplied() { return m_evtsrc_SettingsApplied; } - EventSource& Source_AppStatus() { return m_evtsrc_AppStatus; } - EventSource& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; } - EventSource& Source_SettingsLoadSave() { return m_evtsrc_SettingsLoadSave; } + CmdEvt_Source& Source_CoreThreadStatus() { AffinityAssert_AllowFromMain(); return m_evtsrc_CoreThreadStatus; } + EventSource& Source_SettingsApplied() { AffinityAssert_AllowFromMain(); return m_evtsrc_SettingsApplied; } + EventSource& Source_AppStatus() { AffinityAssert_AllowFromMain(); return m_evtsrc_AppStatus; } + EventSource& Source_CorePluginStatus() { AffinityAssert_AllowFromMain(); return m_evtsrc_CorePluginStatus; } + EventSource& Source_SettingsLoadSave() { AffinityAssert_AllowFromMain(); return m_evtsrc_SettingsLoadSave; } // ---------------------------------------------------------------------------- public: @@ -370,16 +349,13 @@ protected: GSFrame* m_gsFrame; ConsoleLogFrame* m_ProgramLogBox; - std::vector m_PingWhenIdle; wxKeyEvent m_kevt; public: Pcsx2App(); virtual ~Pcsx2App(); - void Ping(); - - void PostPadKey( wxKeyEvent& evt ); + void PostPluginStatus( PluginEventType pevt ); void PostMenuAction( MenuIdentifiers menu_id ) const; int IssueModalDialog( const wxString& dlgName ); @@ -388,6 +364,7 @@ public: void SysExecute(); void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString ); void SysReset(); + void ReloadPlugins(); GSFrame& GetGSFrame() const; GSFrame* GetGSFramePtr() const { return m_gsFrame; } @@ -396,7 +373,8 @@ public: MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; } bool HasMainFrame() const { return m_MainFrame != NULL; } - void OpenGsFrame(); + void OpenGsPanel(); + void CloseGsPanel(); void OnGsFrameClosed(); void OnMainFrameClosed(); @@ -443,31 +421,30 @@ public: void OnProgramLogClosed(); protected: + bool SelfPostMethod( FnType_AppMethod method ); + void InitDefaultGlobalAccelerators(); void BuildCommandHash(); void ReadUserModeSettings(); bool TryOpenConfigCwd(); void CleanupMess(); void OpenWizardConsole(); - void PingDispatch( const char* action ); void PadKeyDispatch( const keyEvent& ev ); void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event) const; void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event); void OnSysExecute( wxCommandEvent& evt ); - void OnReloadPlugins( wxCommandEvent& evt ); void OnLoadPluginsComplete( wxCommandEvent& evt ); + void OnPluginStatus( wxCommandEvent& evt ); void OnOpenModalDialog( wxCommandEvent& evt ); void OnCoreThreadStatus( wxCommandEvent& evt ); void OnFreezeThreadFinished( wxCommandEvent& evt ); - void OnMessageBox( pxMessageBoxEvent& evt ); void OnEmuKeyDown( wxKeyEvent& evt ); void OnLogicalVsync( wxCommandEvent& evt ); - void OnIdleEvent( wxIdleEvent& evt ); - void OnPingEvent( pxPingEvent& evt ); + void OnInvokeMethod( pxInvokeMethodEvent& evt ); // ---------------------------------------------------------------------------- // Override wx default exception handling behavior diff --git a/pcsx2/gui/AppCommon.h b/pcsx2/gui/AppCommon.h index 572d7a1953..7be80039f6 100644 --- a/pcsx2/gui/AppCommon.h +++ b/pcsx2/gui/AppCommon.h @@ -30,7 +30,7 @@ class GSFrame; class ConsoleLogFrame; class PipeRedirectionBase; class AppCoreThread; -class pxPingEvent; +class pxInvokeMethodEvent; // wxWidgets forward declarations @@ -50,8 +50,10 @@ enum PluginEventType { PluginsEvt_Loaded, PluginsEvt_Init, - PluginsEvt_Open, - PluginsEvt_Close, + PluginsEvt_Opening, // dispatched prior to plugins being opened + PluginsEvt_Opened, // dispatched after plugins are opened + PluginsEvt_Closing, // dispatched prior to plugins being closed + PluginsEvt_Closed, // dispatched after plugins are closed PluginsEvt_Shutdown, PluginsEvt_Unloaded, }; diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index a2fa14d099..e8f2bee53c 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -45,10 +45,7 @@ void AppCoreThread::Reset() ScopedBusyCursor::SetDefault( Cursor_KindaBusy ); _parent::Reset(); - - wxCommandEvent evt( pxEVT_CoreThreadStatus ); - evt.SetInt( CoreStatus_Reset ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().PostCommand( pxEvt_CoreThreadStatus, CoreStatus_Reset ); } bool AppCoreThread::Suspend( bool isBlocking ) @@ -92,9 +89,7 @@ void AppCoreThread::Resume() // Resume failed for some reason, so update GUI statuses and post a message to // try again on the resume. - wxCommandEvent evt( pxEVT_CoreThreadStatus ); - evt.SetInt( CoreStatus_Suspended ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().PostCommand( pxEvt_CoreThreadStatus, CoreStatus_Suspended ); if( (m_ExecMode != ExecMode_Closing) || (m_ExecMode != ExecMode_Pausing) ) { @@ -131,30 +126,19 @@ void AppCoreThread::OnResumeReady() AppSaveSettings(); - if( GSopen2 != NULL ) - { - sApp.OpenGsFrame(); - } - _parent::OnResumeReady(); } void AppCoreThread::OnResumeInThread( bool isSuspended ) { _parent::OnResumeInThread( isSuspended ); - - wxCommandEvent evt( pxEVT_CoreThreadStatus ); - evt.SetInt( CoreStatus_Resumed ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().PostCommand( pxEvt_CoreThreadStatus, CoreStatus_Resumed ); } void AppCoreThread::OnSuspendInThread() { _parent::OnSuspendInThread(); - - wxCommandEvent evt( pxEVT_CoreThreadStatus ); - evt.SetInt( CoreStatus_Suspended ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().PostCommand( pxEvt_CoreThreadStatus, CoreStatus_Suspended ); } // Called whenever the thread has terminated, for either regular or irregular reasons. @@ -163,16 +147,13 @@ void AppCoreThread::OnSuspendInThread() // the new (lack of) thread status, so this posts a message to the App to do so. void AppCoreThread::OnCleanupInThread() { - wxCommandEvent evt( pxEVT_CoreThreadStatus ); - evt.SetInt( CoreStatus_Stopped ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().PostCommand( pxEvt_CoreThreadStatus, CoreStatus_Stopped ); _parent::OnCleanupInThread(); } void AppCoreThread::PostVsyncToUI() { - wxCommandEvent evt( pxEVT_LogicalVsync ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().PostCommand( pxEvt_LogicalVsync ); } void AppCoreThread::StateCheckInThread() diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index 56a14744f8..73e904971b 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -260,21 +260,15 @@ bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser ) return true; } -typedef void (wxEvtHandler::*pxMessageBoxEventFunction)(pxMessageBoxEvent&); -typedef void (wxEvtHandler::*pxPingEventFunction)(pxPingEvent&); +typedef void (wxEvtHandler::*pxInvokeMethodEventFunction)(pxInvokeMethodEvent&); // ------------------------------------------------------------------------ bool Pcsx2App::OnInit() { -#define pxMessageBoxEventThing(func) \ - (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxMessageBoxEventFunction, &func ) +#define pxMethodEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxInvokeMethodEventFunction, &func ) -#define pxPingEventHandler(func) \ - (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxPingEventFunction, &func ) - - Connect( pxEVT_MSGBOX, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) ); - Connect( pxEVT_ASSERTION, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) ); - Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) ); + Connect( pxEvt_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) ); pxDoAssert = AppDoAssert; @@ -282,22 +276,23 @@ bool Pcsx2App::OnInit() EnableAllLogging(); wxInitAllImageHandlers(); - if( !wxApp::OnInit() ) return false; + if( !_parent::OnInit() ) return false; m_StdoutRedirHandle = NewPipeRedir(stdout); m_StderrRedirHandle = NewPipeRedir(stderr); wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() ); - Connect( pxEVT_ReloadPlugins, wxCommandEventHandler (Pcsx2App::OnReloadPlugins) ); - Connect( pxEVT_SysExecute, wxCommandEventHandler (Pcsx2App::OnSysExecute) ); + /*Connect( pxEVT_ReloadPlugins, wxCommandEventHandler (Pcsx2App::OnReloadPlugins) ); - Connect( pxEVT_LoadPluginsComplete, wxCommandEventHandler (Pcsx2App::OnLoadPluginsComplete) ); - Connect( pxEVT_CoreThreadStatus, wxCommandEventHandler (Pcsx2App::OnCoreThreadStatus) ); - Connect( pxEVT_FreezeThreadFinished, wxCommandEventHandler (Pcsx2App::OnFreezeThreadFinished) ); Connect( pxEVT_LogicalVsync, wxCommandEventHandler (Pcsx2App::OnLogicalVsync) ); + Connect( pxEVT_OpenGsPanel, wxCommandEventHandler (Pcsx2App::OpenGsPanel) );*/ - Connect( pxEVT_Ping, pxPingEventHandler (Pcsx2App::OnPingEvent) ); - Connect( wxEVT_IDLE, wxIdleEventHandler (Pcsx2App::OnIdleEvent) ); + Connect( pxEvt_FreezeThreadFinished, wxCommandEventHandler (Pcsx2App::OnFreezeThreadFinished) ); + Connect( pxEvt_CoreThreadStatus, wxCommandEventHandler (Pcsx2App::OnCoreThreadStatus) ); + Connect( pxEvt_LoadPluginsComplete, wxCommandEventHandler (Pcsx2App::OnLoadPluginsComplete) ); + Connect( pxEvt_PluginStatus, wxCommandEventHandler (Pcsx2App::OnPluginStatus) ); + Connect( pxEvt_SysExecute, wxCommandEventHandler (Pcsx2App::OnSysExecute) ); + Connect( pxEvt_InvokeMethod, pxMethodEventHandler (Pcsx2App::OnInvokeMethod) ); Connect( pxID_PadHandler_Keydown, wxEVT_KEY_DOWN, wxKeyEventHandler( Pcsx2App::OnEmuKeyDown ) ); @@ -518,16 +513,6 @@ Pcsx2App::Pcsx2App() SetAppName( L"pcsx2" ); BuildCommandHash(); - -#ifdef __WXMSW__ - // This variable assignment ensures that MSVC links in the TLS setup stubs even in - // full optimization builds. Without it, DLLs that use TLS won't work because the - // FS segment register won't have been initialized by the main exe, due to tls_insurance - // being optimized away >_< --air - - static __threadlocal int tls_insurance = 0; - tls_insurance = 1; -#endif } Pcsx2App::~Pcsx2App() diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index f952b6a96e..95420be63d 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -32,14 +32,17 @@ IMPLEMENT_APP(Pcsx2App) -DEFINE_EVENT_TYPE( pxEVT_OpenModalDialog ); -DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins ); -DEFINE_EVENT_TYPE( pxEVT_SysExecute ); -DEFINE_EVENT_TYPE( pxEVT_LoadPluginsComplete ); -DEFINE_EVENT_TYPE( pxEVT_CoreThreadStatus ); -DEFINE_EVENT_TYPE( pxEVT_FreezeThreadFinished ); -DEFINE_EVENT_TYPE( pxEVT_Ping ); -DEFINE_EVENT_TYPE( pxEVT_LogicalVsync ); +/*DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins ); +DEFINE_EVENT_TYPE( pxEVT_OpenGsPanel );*/ + +DEFINE_EVENT_TYPE( pxEvt_FreezeThreadFinished ); +DEFINE_EVENT_TYPE( pxEvt_CoreThreadStatus ); +DEFINE_EVENT_TYPE( pxEvt_LoadPluginsComplete ); +DEFINE_EVENT_TYPE( pxEvt_PluginStatus ); +DEFINE_EVENT_TYPE( pxEvt_SysExecute ); +DEFINE_EVENT_TYPE( pxEvt_OpenModalDialog ); +DEFINE_EVENT_TYPE( pxEvt_InvokeMethod ); +DEFINE_EVENT_TYPE( pxEvt_LogicalVsync ); #include "Utilities/EventSource.inl" EventSource_ImplementType( IniInterface ); @@ -85,72 +88,66 @@ void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const m_MainFrame->GetEventHandler()->AddPendingEvent( joe ); } -class pxPingEvent : public wxEvent +// -------------------------------------------------------------------------------------- +// pxInvokeMethodEvent +// -------------------------------------------------------------------------------------- +// Unlike pxPingEvent, the Semaphore belonging to this event is typically posted when the +// invoked method is completed. If the method can be executed in non-blocking fashion then +// it should leave the semaphore postback NULL. +// +class pxInvokeMethodEvent : public pxPingEvent { - DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxPingEvent) + DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxInvokeMethodEvent) protected: - Semaphore* m_PostBack; + FnType_AppMethod m_Method; public: - virtual ~pxPingEvent() throw() { } - virtual pxPingEvent *Clone() const { return new pxPingEvent(*this); } + virtual ~pxInvokeMethodEvent() throw() { } + virtual pxInvokeMethodEvent *Clone() const { return new pxInvokeMethodEvent(*this); } - explicit pxPingEvent( int msgtype, Semaphore* sema=NULL ) - : wxEvent( 0, msgtype ) + explicit pxInvokeMethodEvent( int msgtype, FnType_AppMethod method=NULL, Semaphore* sema=NULL ) + : pxPingEvent( msgtype, sema ) { - m_PostBack = sema; + m_Method = method; } - explicit pxPingEvent( Semaphore* sema=NULL ) - : wxEvent( 0, pxEVT_Ping ) + explicit pxInvokeMethodEvent( FnType_AppMethod method=NULL, Semaphore* sema=NULL ) + : pxPingEvent( pxEvt_InvokeMethod, sema ) { - m_PostBack = sema; + m_Method = method; + } + + explicit pxInvokeMethodEvent( FnType_AppMethod method, Semaphore& sema ) + : pxPingEvent( pxEvt_InvokeMethod, &sema ) + { + m_Method = method; } - pxPingEvent( const pxPingEvent& src ) - : wxEvent( src ) + pxInvokeMethodEvent( const pxInvokeMethodEvent& src ) + : pxPingEvent( src ) { - m_PostBack = src.m_PostBack; + m_Method = src.m_Method; + } + + void Invoke() const + { + if( m_Method ) (wxGetApp().*m_Method)(); + if( m_PostBack ) m_PostBack->Post(); } - Semaphore* GetSemaphore() { return m_PostBack; } + void SetMethod( FnType_AppMethod method ) + { + m_Method = method; + } }; -IMPLEMENT_DYNAMIC_CLASS( pxPingEvent, wxEvent ) -void Pcsx2App::OnPingEvent( pxPingEvent& evt ) +IMPLEMENT_DYNAMIC_CLASS( pxInvokeMethodEvent, pxPingEvent ) + +void Pcsx2App::OnInvokeMethod( pxInvokeMethodEvent& evt ) { - m_PingWhenIdle.push_back( evt.GetSemaphore() ); -} - -void Pcsx2App::PingDispatch( const char* action ) -{ - size_t size = m_PingWhenIdle.size(); - if( size == 0 ) return; - - DbgCon.WriteLn( Color_Gray, "App Event Ping (%s) -> %u listeners.", action, size ); - - for( size_t i=0; iPost(); - } - - m_PingWhenIdle.clear(); -} - -void Pcsx2App::OnIdleEvent( wxIdleEvent& evt ) -{ - evt.Skip(); - PingDispatch( "Idle" ); -} - -void Pcsx2App::Ping() -{ - Semaphore sema; - pxPingEvent evt( &sema ); - AddPendingEvent( evt ); - sema.WaitNoCancel(); + evt.Invoke(); // wow this is easy! } #ifdef __WXGTK__ @@ -268,10 +265,7 @@ int Pcsx2App::IssueModalDialog( const wxString& dlgName ) if( !wxThread::IsMain() ) { MsgboxEventResult result; - wxCommandEvent joe( pxEVT_OpenModalDialog ); - joe.SetString( dlgName ); - joe.SetClientData( &result ); - AddPendingEvent( joe ); + PostCommand( &result, pxEvt_OpenModalDialog, 0, 0, dlgName ); result.WaitForMe.WaitNoCancel(); return result.result; } @@ -608,20 +602,55 @@ void AppSaveSettings() wxGetApp().Source_SettingsLoadSave().Dispatch( saver ); } -void Pcsx2App::OpenGsFrame() +// This function works something like setjmp/longjmp, in that the return value indicates if the +// function actually executed the specified method or not. +// +// Returns: +// FALSE if the method was not posted to the main thread (meaning this IS the main thread!) +// TRUE if the method was posted. +// +bool Pcsx2App::SelfPostMethod( FnType_AppMethod method ) { + if( wxThread::IsMain() ) return false; + + Semaphore sem; + pxInvokeMethodEvent evt( method, sem ); + AddPendingEvent( evt ); + sem.Wait(); + + return true; +} + +void Pcsx2App::OpenGsPanel() +{ + if( SelfPostMethod( &Pcsx2App::OpenGsPanel ) ) return; + if( m_gsFrame == NULL ) { m_gsFrame = new GSFrame( m_MainFrame, L"PCSX2" ); m_gsFrame->SetFocus(); - pDsp = (uptr)m_gsFrame->GetViewport()->GetHandle(); } + + pxAssumeDev( !GetPluginManager().IsOpen( PluginId_GS ), "GS Plugin must be closed prior to opening a new Gs Panel!" ); + m_gsFrame->Show(); + pDsp = (uptr)m_gsFrame->GetViewport()->GetHandle(); // The "in the main window" quickie hack... //pDsp = (uptr)m_MainFrame->m_background.GetHandle(); } +void Pcsx2App::CloseGsPanel() +{ + if( SelfPostMethod( &Pcsx2App::CloseGsPanel ) ) return; + + if( m_gsFrame != NULL ) + { + if( GSPanel* woot = (GSPanel*)m_gsFrame->FindWindowByName(L"GSPanel") ) + woot->Destroy(); + } +} + void Pcsx2App::OnGsFrameClosed() { CoreThread.Suspend(); @@ -659,10 +688,7 @@ static void _sendmsg_SysExecute() } AppSaveSettings(); - - wxCommandEvent execevt( pxEVT_SysExecute ); - execevt.SetInt( _sysexec_cdvdsrc_type ); - wxGetApp().AddPendingEvent( execevt ); + wxGetApp().PostCommand( pxEvt_SysExecute, _sysexec_cdvdsrc_type ); } static void OnSysExecuteAfterPlugins( const wxCommandEvent& loadevt ) @@ -683,6 +709,8 @@ void Pcsx2App::SysExecute() LoadPluginsPassive( OnSysExecuteAfterPlugins ); return; } + + DbgCon.WriteLn( Color_Gray, "(SysExecute) Queuing request to re-execute existing VM state." ); _sendmsg_SysExecute(); } @@ -699,6 +727,8 @@ void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override LoadPluginsPassive( OnSysExecuteAfterPlugins ); return; } + + DbgCon.WriteLn( Color_Gray, "(SysExecute) Queuing request for new VM state." ); _sendmsg_SysExecute(); } @@ -719,6 +749,8 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt ) // it, because apparently too much stuff is going on and the emulation states are wonky. if( !m_CorePlugins ) return; + DbgCon.WriteLn( Color_Gray, "(MainThread) SysExecute received." ); + if( evt.GetInt() != -1 ) CoreThread.Reset(); else CoreThread.Suspend(); CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso ); if( evt.GetInt() != -1 ) diff --git a/pcsx2/gui/Dialogs/ModalPopups.h b/pcsx2/gui/Dialogs/ModalPopups.h index 69ce30ae36..6b54c82d22 100644 --- a/pcsx2/gui/Dialogs/ModalPopups.h +++ b/pcsx2/gui/Dialogs/ModalPopups.h @@ -67,94 +67,6 @@ protected: virtual void OnDoubleClicked( wxCommandEvent& evt ); }; -class MsgButtons -{ -protected: - BITFIELD32() - bool - m_OK :1, - m_Cancel :1, - m_Yes :1, - m_No :1, - m_AllowToAll:1, - m_Apply :1, - m_Abort :1, - m_Retry :1, - m_Ignore :1, - m_Reset :1, - m_Close :1; - BITFIELD_END - - wxString m_CustomLabel; - -public: - MsgButtons() : bitset( 0 ) { } - - MsgButtons& OK() { m_OK = true; return *this; } - MsgButtons& Cancel() { m_Cancel = true; return *this; } - MsgButtons& Apply() { m_Apply = true; return *this; } - MsgButtons& Yes() { m_Yes = true; return *this; } - MsgButtons& No() { m_No = true; return *this; } - MsgButtons& ToAll() { m_AllowToAll = true; return *this; } - - MsgButtons& Abort() { m_Abort = true; return *this; } - MsgButtons& Retry() { m_Retry = true; return *this; } - MsgButtons& Ignore() { m_Ignore = true; return *this; } - MsgButtons& Reset() { m_Reset = true; return *this; } - MsgButtons& Close() { m_Close = true; return *this; } - - MsgButtons& Custom( const wxString& label) - { - m_CustomLabel = label; - return *this; - } - - MsgButtons& OKCancel() { m_OK = m_Cancel = true; return *this; } - MsgButtons& YesNo() { m_Yes = m_No = true; return *this; } - - bool HasOK() const { return m_OK; } - bool HasCancel() const { return m_Cancel; } - bool HasApply() const { return m_Apply; } - bool HasYes() const { return m_Yes; } - bool HasNo() const { return m_No; } - bool AllowsToAll() const{ return m_AllowToAll; } - - bool HasAbort() const { return m_Abort; } - bool HasRetry() const { return m_Retry; } - bool HasIgnore() const { return m_Ignore; } - bool HasReset() const { return m_Reset; } - bool HasClose() const { return m_Close; } - - bool HasCustom() const { return !m_CustomLabel.IsEmpty(); } - const wxString& GetCustomLabel() const { return m_CustomLabel; } - - bool Allows( wxWindowID id ) const; - void SetBestFocus( wxWindow* dialog ) const; - void SetBestFocus( wxWindow& dialog ) const; - - bool operator ==( const MsgButtons& right ) const - { - return OpEqu( bitset ); - } - - bool operator !=( const MsgButtons& right ) const - { - return !OpEqu( bitset ); - } -}; - -class ModalButtonPanel : public wxPanelWithHelpers -{ -public: - ModalButtonPanel( wxWindow* window, const MsgButtons& buttons ); - virtual ~ModalButtonPanel() throw() { } - - virtual void AddActionButton( wxWindowID id ); - virtual void AddCustomButton( wxWindowID id, const wxString& label ); - - virtual void OnActionButtonClicked( wxCommandEvent& evt ); -}; - namespace Dialogs { class AboutBoxDialog: public wxDialogWithHelpers diff --git a/pcsx2/gui/FrameForGS.cpp b/pcsx2/gui/FrameForGS.cpp index 66bce9922c..1827ae0ff4 100644 --- a/pcsx2/gui/FrameForGS.cpp +++ b/pcsx2/gui/FrameForGS.cpp @@ -47,7 +47,7 @@ void GSPanel::InitDefaultAccelerators() GSPanel::GSPanel( wxWindow* parent ) : wxWindow() - , m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener ( this, OnSettingsApplied ) ) + , m_Listener_SettingsApplied ( wxGetApp().Source_SettingsApplied(), EventListener ( this, OnSettingsApplied ) ) , m_HideMouseTimer( this ) { m_CursorShown = true; @@ -66,29 +66,29 @@ GSPanel::GSPanel( wxWindow* parent ) m_CursorShown = false; } - Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSPanel::OnCloseWindow) ); - Connect( wxEVT_SIZE, wxSizeEventHandler (GSPanel::OnResize) ); - Connect( wxEVT_KEY_DOWN, wxKeyEventHandler (GSPanel::OnKeyDown) ); + Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSPanel::OnCloseWindow)); + Connect(wxEVT_SIZE, wxSizeEventHandler (GSPanel::OnResize)); + Connect(wxEVT_KEY_DOWN, wxKeyEventHandler (GSPanel::OnKeyDown)); - Connect( wxEVT_SET_FOCUS, wxFocusEventHandler(GSPanel::OnFocus) ); - Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler(GSPanel::OnFocusLost) ); + Connect(wxEVT_SET_FOCUS, wxFocusEventHandler (GSPanel::OnFocus)); + Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler (GSPanel::OnFocusLost)); - Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_MOTION, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler(GSPanel::OnShowMouse) ); - Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(GSPanel::OnShowMouse) ); + Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_RIGHT_UP, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_MOTION, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_MIDDLE_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_RIGHT_DCLICK, wxMouseEventHandler (GSPanel::OnShowMouse)); + Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler (GSPanel::OnShowMouse)); Connect(m_HideMouseTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(GSPanel::OnHideMouseTimeout) ); } GSPanel::~GSPanel() throw() { - CoreThread.Suspend(); // Just in case...! + CoreThread.Suspend( false ); // Just in case...! } void GSPanel::DoShowMouse() @@ -246,9 +246,10 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title) label->SetName(L"OutputDisabledLabel"); label->SetFont( *new wxFont( 20, wxDEFAULT, wxNORMAL, wxBOLD ) ); label->SetForegroundColour( *wxWHITE ); - label->Show( !EmuConfig.GS.DisableOutput ); + label->Show( EmuConfig.GS.DisableOutput ); - m_gspanel = new GSPanel( this ); + m_gspanel = new GSPanel( this ); // TODO : give this an id instead of using FindByName + m_gspanel->Show( !EmuConfig.GS.DisableOutput ); //Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSFrame::OnCloseWindow) ); Connect( wxEVT_MOVE, wxMoveEventHandler (GSFrame::OnMove) ); @@ -260,6 +261,24 @@ GSFrame::~GSFrame() throw() { } +// overrides base Show behavior. +bool GSFrame::Show( bool shown ) +{ + if( shown ) + { + if( FindWindowByName(L"GSPanel") == NULL ) + { + m_gspanel = new GSPanel( this ); + m_gspanel->Show( !EmuConfig.GS.DisableOutput ); + } + + m_gspanel->DoResize(); + m_gspanel->SetFocus(); + } + + return _parent::Show( shown ); +} + void __evt_fastcall GSFrame::OnSettingsApplied( void* obj, int& evt ) { if( obj == NULL ) return; @@ -280,7 +299,7 @@ void GSFrame::DoSettingsApplied() wxWindow* GSFrame::GetViewport() { - return m_gspanel; + return FindWindowByName(L"GSPanel"); } void GSFrame::OnActivate( wxActivateEvent& evt ) diff --git a/pcsx2/gui/IniInterface.cpp b/pcsx2/gui/IniInterface.cpp index 6d32e03289..65baa67f9e 100644 --- a/pcsx2/gui/IniInterface.cpp +++ b/pcsx2/gui/IniInterface.cpp @@ -78,7 +78,7 @@ IniLoader::IniLoader( wxConfigBase& config ) : IniInterface( config ) } IniLoader::IniLoader() : IniInterface() {} -IniLoader::~IniLoader() {} +IniLoader::~IniLoader() throw() {} void IniLoader::Entry( const wxString& var, wxString& value, const wxString& defvalue ) diff --git a/pcsx2/gui/IniInterface.h b/pcsx2/gui/IniInterface.h index 84b7021eb8..32231d5e9c 100644 --- a/pcsx2/gui/IniInterface.h +++ b/pcsx2/gui/IniInterface.h @@ -99,7 +99,7 @@ public: class IniLoader : public IniInterface { public: - virtual ~IniLoader(); + virtual ~IniLoader() throw(); explicit IniLoader(); explicit IniLoader( wxConfigBase& config ); diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index 6842bcd886..220b09acb7 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -67,6 +67,8 @@ protected: // -------------------------------------------------------------------------------------- class GSFrame : public wxFrame { + typedef wxFrame _parent; + protected: EventListenerBinding m_Listener_SettingsApplied; GSPanel* m_gspanel; @@ -78,6 +80,8 @@ public: wxWindow* GetViewport(); + bool Show( bool shown=true ); + protected: void OnMove( wxMoveEvent& evt ); void OnResize( wxSizeEvent& evt ); diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index 95f0f4a989..737c990d5f 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -240,16 +240,16 @@ void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent &event) { if( !SysHasValidState() ) return; - if( !CoreThread.Suspend() ) - { - sApp.SysExecute(); - } - // Disable the menu item. The state of the menu is indeterminate until the core thread // has responded (it updates status after the plugins are loaded and emulation has // engaged successfully). GetMenuBar()->Enable( MenuId_Sys_SuspendResume, false ); + + if( !CoreThread.Suspend() ) + { + sApp.SysExecute(); + } } void MainEmuFrame::Menu_SysReset_Click(wxCommandEvent &event) diff --git a/pcsx2/gui/MessageBoxes.cpp b/pcsx2/gui/MessageBoxes.cpp index 887d95f0d2..b86a0c674e 100644 --- a/pcsx2/gui/MessageBoxes.cpp +++ b/pcsx2/gui/MessageBoxes.cpp @@ -17,9 +17,6 @@ #include "App.h" #include "Dialogs/ModalPopups.h" -DEFINE_EVENT_TYPE( pxEVT_MSGBOX ); -DEFINE_EVENT_TYPE( pxEVT_ASSERTION ); - using namespace Threading; using namespace pxSizerFlags; @@ -43,206 +40,152 @@ static int pxMessageDialog( const wxString& caption, const wxString& content, co return pxIssueConfirmation( dialog, buttons ); } -class BaseMessageBoxEvent : public wxEvent -{ - DECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent) - -protected: - MsgboxEventResult* m_Instdata; - wxString m_Content; - -public: - explicit BaseMessageBoxEvent( int msgtype=pxEVT_MSGBOX, const wxString& content=wxEmptyString ) - : wxEvent( 0, msgtype ) - , m_Content( content ) - { - m_Instdata = NULL; - } - - virtual ~BaseMessageBoxEvent() throw() { } - virtual BaseMessageBoxEvent *Clone() const { return new BaseMessageBoxEvent(*this); } - - BaseMessageBoxEvent( MsgboxEventResult& instdata, const wxString& content ) - : wxEvent( 0, pxEVT_MSGBOX ) - , m_Instdata( &instdata ) - , m_Content( content ) - { - } - - BaseMessageBoxEvent( const wxString& content ) - : wxEvent( 0, pxEVT_MSGBOX ) - , m_Instdata( NULL ) - , m_Content( content ) - { - } - - BaseMessageBoxEvent( const BaseMessageBoxEvent& event ) - : wxEvent( event ) - , m_Instdata( event.m_Instdata ) - , m_Content( event.m_Content ) - { - } - - BaseMessageBoxEvent& SetInstData( MsgboxEventResult& instdata ) - { - m_Instdata = &instdata; - return *this; - } - - // Thread Safety: Must be called from the GUI thread ONLY. - virtual void IssueDialog() - { - AffinityAssert_AllowFromMain(); - - int result = _DoDialog(); - - if( m_Instdata != NULL ) - { - m_Instdata->result = result; - m_Instdata->WaitForMe.Post(); - } - } - -protected: - virtual int _DoDialog() const - { - pxFailDev( "Abstract Base MessageBox Event." ); - return wxID_CANCEL; - } -}; - // -------------------------------------------------------------------------------------- -// pxMessageBoxEvent +// BaseMessageBoxEvent Implementation // -------------------------------------------------------------------------------------- -// This event type is used to transfer message boxes to the main UI thread, and return the -// result of the box. It's the only way a message box can be issued from non-main threads -// with complete safety in wx2.8. -// -// For simplicity sake this message box only supports two basic designs. The main design -// is a generic message box with confirmation buttons of your choosing. Additionally you -// can specify a "scrollableContent" text string, which is added into a read-only richtext -// control similar to the console logs and such. -// -// Future consideration: If wxWidgets 3.0 has improved thread safety, then it should probably -// be reasonable for it to work with a more flexable model where the dialog can be created -// on a child thread, passed to the main thread, where ShowModal() is run (keeping the nested -// message pumps on the main thread where they belong). But so far this is not possible, -// because of various subtle issues in wx2.8 design. -// -class pxMessageBoxEvent : public BaseMessageBoxEvent -{ - typedef BaseMessageBoxEvent _parent; - DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent) - -protected: - wxString m_Title; - MsgButtons m_Buttons; - -public: - pxMessageBoxEvent( int msgtype=pxEVT_MSGBOX ) - : BaseMessageBoxEvent( msgtype ) - { - } - - virtual ~pxMessageBoxEvent() throw() { } - virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); } - - pxMessageBoxEvent( MsgboxEventResult& instdata, const wxString& title, const wxString& content, const MsgButtons& buttons ) - : BaseMessageBoxEvent( instdata, content ) - , m_Title( title ) - , m_Buttons( buttons ) - { - } - - pxMessageBoxEvent( const wxString& title, const wxString& content, const MsgButtons& buttons ) - : BaseMessageBoxEvent( content ) - , m_Title( title ) - , m_Buttons( buttons ) - { - } - - pxMessageBoxEvent( const pxMessageBoxEvent& event ) - : BaseMessageBoxEvent( event ) - , m_Title( event.m_Title ) - , m_Buttons( event.m_Buttons ) - { - } - - pxMessageBoxEvent& SetInstData( MsgboxEventResult& instdata ) - { - _parent::SetInstData( instdata ); - return *this; - } - -protected: - virtual int _DoDialog() const - { - return pxMessageDialog( m_Content, m_Title, m_Buttons ); - } -}; - -// -------------------------------------------------------------------------------------- -// pxAssertionEvent -// -------------------------------------------------------------------------------------- -class pxAssertionEvent : public BaseMessageBoxEvent -{ - typedef BaseMessageBoxEvent _parent; - DECLARE_DYNAMIC_CLASS_NO_ASSIGN( pxAssertionEvent ) - -protected: - wxString m_Stacktrace; - -public: - pxAssertionEvent() - : BaseMessageBoxEvent( pxEVT_ASSERTION ) - { - } - - virtual ~pxAssertionEvent() throw() { } - - virtual pxAssertionEvent *Clone() const { return new pxAssertionEvent(*this); } - - pxAssertionEvent( MsgboxEventResult& instdata, const wxString& content, const wxString& trace ) - : BaseMessageBoxEvent( pxEVT_ASSERTION ) - , m_Stacktrace( trace ) - { - } - - pxAssertionEvent( const wxString& content, const wxString& trace ) - : BaseMessageBoxEvent( pxEVT_ASSERTION, content ) - , m_Stacktrace( trace ) - { - } - - pxAssertionEvent( const pxAssertionEvent& event ) - : BaseMessageBoxEvent( event ) - , m_Stacktrace( event.m_Stacktrace ) - { - } - - pxAssertionEvent& SetInstData( MsgboxEventResult& instdata ) - { - _parent::SetInstData( instdata ); - return *this; - } - - pxAssertionEvent& SetStacktrace( const wxString& trace ) - { - m_Stacktrace = trace; - return *this; - } - -protected: - virtual int _DoDialog() const - { - return Dialogs::AssertionDialog( m_Content, m_Stacktrace ).ShowModal(); - } -}; - IMPLEMENT_DYNAMIC_CLASS( BaseMessageBoxEvent, wxEvent ) + +BaseMessageBoxEvent::BaseMessageBoxEvent( int msgtype, const wxString& content ) + : wxEvent( 0, msgtype ) + , m_Content( content ) +{ + m_Instdata = NULL; +} + +BaseMessageBoxEvent::BaseMessageBoxEvent( MsgboxEventResult& instdata, const wxString& content ) + : wxEvent( 0, pxEvt_MessageBox ) + , m_Instdata( &instdata ) + , m_Content( content ) +{ +} + +BaseMessageBoxEvent::BaseMessageBoxEvent( const wxString& content ) + : wxEvent( 0, pxEvt_MessageBox ) + , m_Instdata( NULL ) + , m_Content( content ) +{ +} + +BaseMessageBoxEvent::BaseMessageBoxEvent( const BaseMessageBoxEvent& event ) + : wxEvent( event ) + , m_Instdata( event.m_Instdata ) + , m_Content( event.m_Content ) +{ +} + +BaseMessageBoxEvent& BaseMessageBoxEvent::SetInstData( MsgboxEventResult& instdata ) +{ + m_Instdata = &instdata; + return *this; +} + +// Thread Safety: Must be called from the GUI thread ONLY. +void BaseMessageBoxEvent::IssueDialog() +{ + AffinityAssert_AllowFromMain(); + + int result = _DoDialog(); + + if( m_Instdata != NULL ) + { + m_Instdata->result = result; + m_Instdata->WaitForMe.Post(); + } +} + +int BaseMessageBoxEvent::_DoDialog() const +{ + pxFailDev( "Abstract Base MessageBox Event." ); + return wxID_CANCEL; +} + +// -------------------------------------------------------------------------------------- +// pxMessageBoxEvent Implementation +// -------------------------------------------------------------------------------------- IMPLEMENT_DYNAMIC_CLASS( pxMessageBoxEvent, BaseMessageBoxEvent ) + +pxMessageBoxEvent::pxMessageBoxEvent( int msgtype ) + : BaseMessageBoxEvent( msgtype ) +{ +} + +pxMessageBoxEvent::pxMessageBoxEvent( MsgboxEventResult& instdata, const wxString& title, const wxString& content, const MsgButtons& buttons ) + : BaseMessageBoxEvent( instdata, content ) + , m_Title( title ) + , m_Buttons( buttons ) +{ +} + +pxMessageBoxEvent::pxMessageBoxEvent( const wxString& title, const wxString& content, const MsgButtons& buttons ) + : BaseMessageBoxEvent( content ) + , m_Title( title ) + , m_Buttons( buttons ) +{ +} + +pxMessageBoxEvent::pxMessageBoxEvent( const pxMessageBoxEvent& event ) + : BaseMessageBoxEvent( event ) + , m_Title( event.m_Title ) + , m_Buttons( event.m_Buttons ) +{ +} + +pxMessageBoxEvent& pxMessageBoxEvent::SetInstData( MsgboxEventResult& instdata ) +{ + _parent::SetInstData( instdata ); + return *this; +} + +int pxMessageBoxEvent::_DoDialog() const +{ + return pxMessageDialog( m_Content, m_Title, m_Buttons ); +} + +// -------------------------------------------------------------------------------------- +// pxAssertionEvent Implementation +// -------------------------------------------------------------------------------------- IMPLEMENT_DYNAMIC_CLASS( pxAssertionEvent, BaseMessageBoxEvent ) +pxAssertionEvent::pxAssertionEvent() + : BaseMessageBoxEvent( pxEvt_Assertion ) +{ +} + +pxAssertionEvent::pxAssertionEvent( MsgboxEventResult& instdata, const wxString& content, const wxString& trace ) + : BaseMessageBoxEvent( pxEvt_Assertion ) + , m_Stacktrace( trace ) +{ +} + +pxAssertionEvent::pxAssertionEvent( const wxString& content, const wxString& trace ) + : BaseMessageBoxEvent( pxEvt_Assertion, content ) + , m_Stacktrace( trace ) +{ +} + +pxAssertionEvent::pxAssertionEvent( const pxAssertionEvent& event ) + : BaseMessageBoxEvent( event ) + , m_Stacktrace( event.m_Stacktrace ) +{ +} + +pxAssertionEvent& pxAssertionEvent::SetInstData( MsgboxEventResult& instdata ) +{ + _parent::SetInstData( instdata ); + return *this; +} + +pxAssertionEvent& pxAssertionEvent::SetStacktrace( const wxString& trace ) +{ + m_Stacktrace = trace; + return *this; +} + +int pxAssertionEvent::_DoDialog() const +{ + return Dialogs::AssertionDialog( m_Content, m_Stacktrace ).ShowModal(); +} + namespace Msgbox { static int ThreadedMessageBox( BaseMessageBoxEvent& evt ) @@ -325,8 +268,3 @@ namespace Msgbox return ThreadedMessageBox( tevt ); } } - -void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt ) -{ - evt.IssueDialog(); -} diff --git a/pcsx2/gui/Plugins.cpp b/pcsx2/gui/Plugins.cpp index c87d4a59c5..d3b8e7e30b 100644 --- a/pcsx2/gui/Plugins.cpp +++ b/pcsx2/gui/Plugins.cpp @@ -50,51 +50,73 @@ public: virtual ~AppPluginManager() throw() { - PluginEventType pevt = PluginsEvt_Unloaded; - sApp.Source_CorePluginStatus().Dispatch( pevt ); + sApp.PostPluginStatus( PluginsEvt_Unloaded ); } void Init() { SetSettingsFolder( GetSettingsFolder().ToString() ); - _parent::Init(); - - PluginEventType pevt = PluginsEvt_Init; - sApp.Source_CorePluginStatus().Dispatch( pevt ); + sApp.PostPluginStatus( PluginsEvt_Init ); } void Shutdown() { _parent::Shutdown(); - - PluginEventType pevt = PluginsEvt_Shutdown; - sApp.Source_CorePluginStatus().Dispatch( pevt ); + sApp.PostPluginStatus( PluginsEvt_Shutdown ); } void Close() { + if( !NeedsClose() ) return; + + sApp.PostPluginStatus( PluginsEvt_Closing ); _parent::Close(); - - PluginEventType pevt = PluginsEvt_Close; - sApp.Source_CorePluginStatus().Dispatch( pevt ); + sApp.PostPluginStatus( PluginsEvt_Closed ); } void Open() { SetSettingsFolder( GetSettingsFolder().ToString() ); - _parent::Open(); + if( !NeedsOpen() ) return; - PluginEventType pevt = PluginsEvt_Open; - sApp.Source_CorePluginStatus().Dispatch( pevt ); + sApp.PostPluginStatus( PluginsEvt_Opening ); + _parent::Open(); + sApp.PostPluginStatus( PluginsEvt_Opened ); } + + bool OpenPlugin_GS() + { + if( GSopen2 != NULL ) + { + sApp.OpenGsPanel(); + } + + return _parent::OpenPlugin_GS(); + } + + void ClosePlugin_GS() + { + _parent::ClosePlugin_GS(); + sApp.CloseGsPanel(); + } + + + /*void Open( PluginsEnum_t pid ) + { + _parent::Open( pid ); + } + + void Close( PluginsEnum_t pid ) + { + }*/ }; // -------------------------------------------------------------------------------------- // LoadPluginsTask // -------------------------------------------------------------------------------------- -// On completion the thread sends a pxEVT_LoadPluginsComplete message, which contains a +// On completion the thread sends a pxEvt_LoadPluginsComplete message, which contains a // handle to this thread object. If the load is successful, the Result var is set to // non-NULL. If NULL, an error occurred and the thread loads the exception into either // Ex_PluginError or Ex_RuntimeError. @@ -140,10 +162,7 @@ void LoadPluginsTask::ExecuteTaskInThread() void LoadPluginsTask::OnCleanupInThread() { - wxCommandEvent evt( pxEVT_LoadPluginsComplete ); - evt.SetClientData( this ); - wxGetApp().AddPendingEvent( evt ); - + wxGetApp().PostCommand( this, pxEvt_LoadPluginsComplete ); _parent::OnCleanupInThread(); } @@ -225,8 +244,10 @@ void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] ) // boolean lock modified from the main thread only... static bool plugin_load_lock = false; -void Pcsx2App::OnReloadPlugins( wxCommandEvent& evt ) +void Pcsx2App::ReloadPlugins() { + if( SelfPostMethod( &Pcsx2App::ReloadPlugins ) ) return; + if( plugin_load_lock ) return; CoreThread.Cancel(); m_CorePlugins = NULL; @@ -268,9 +289,24 @@ void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt ) if( fn_tmp != NULL ) fn_tmp( evt ); - PluginEventType pevt = PluginsEvt_Loaded; - sApp.Source_CorePluginStatus().Dispatch( pevt ); - Source_CorePluginStatus().Dispatch( pevt ); + PostPluginStatus( PluginsEvt_Loaded ); +} + +void Pcsx2App::PostPluginStatus( PluginEventType pevt ) +{ + if( !wxThread::IsMain() ) + { + PostCommand( pxEvt_PluginStatus, pevt ); + } + else + { + sApp.Source_CorePluginStatus().Dispatch( pevt ); + } +} + +void Pcsx2App::OnPluginStatus( wxCommandEvent& evt ) +{ + PostPluginStatus( (PluginEventType)evt.GetInt() ); } // Posts a message to the App to reload plugins. Plugins are loaded via a background thread @@ -282,15 +318,14 @@ void LoadPluginsPassive( FnType_OnThreadComplete* onComplete ) // Plugins already loaded? if( wxGetApp().m_CorePlugins ) { - if( onComplete ) onComplete( wxCommandEvent( pxEVT_LoadPluginsComplete ) ); + if( onComplete ) onComplete( wxCommandEvent( pxEvt_LoadPluginsComplete ) ); return; } if( onComplete ) Callback_PluginsLoadComplete = onComplete; - wxCommandEvent evt( pxEVT_ReloadPlugins ); - wxGetApp().AddPendingEvent( evt ); + wxGetApp().ReloadPlugins(); } // Performs a blocking load of plugins. If the emulation thread is active, it is shut down diff --git a/pcsx2/gui/wxAppWithHelpers.cpp b/pcsx2/gui/wxAppWithHelpers.cpp new file mode 100644 index 0000000000..9958f3ba30 --- /dev/null +++ b/pcsx2/gui/wxAppWithHelpers.cpp @@ -0,0 +1,149 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "wxAppWithHelpers.h" + +DEFINE_EVENT_TYPE( pxEvt_Ping ); +DEFINE_EVENT_TYPE( pxEvt_MessageBox ); +DEFINE_EVENT_TYPE( pxEvt_Assertion ); + +// -------------------------------------------------------------------------------------- +// pxPingEvent Implementations +// -------------------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS( pxPingEvent, wxEvent ) + +pxPingEvent::pxPingEvent( int msgtype, Semaphore* sema ) + : wxEvent( 0, msgtype ) +{ + m_PostBack = sema; +} + +pxPingEvent::pxPingEvent( Semaphore* sema ) + : wxEvent( 0, pxEvt_Ping ) +{ + m_PostBack = sema; +} + +pxPingEvent::pxPingEvent( const pxPingEvent& src ) + : wxEvent( src ) +{ + m_PostBack = src.m_PostBack; +} + +void wxAppWithHelpers::OnPingEvent( pxPingEvent& evt ) +{ + // Ping events are dispatched during the idle event handler, which ensures + // the ping is posted only after all other pending messages behind the ping + // are also processed. + + m_PingWhenIdle.push_back( evt.GetSemaphore() ); + m_PingTimer.Start( 200, true ); +} + +void wxAppWithHelpers::PingDispatch( const char* action ) +{ + size_t size = m_PingWhenIdle.size(); + if( size == 0 ) return; + + DbgCon.WriteLn( Color_Gray, "App Event Ping (%s) -> %u listeners.", action, size ); + + for( size_t i=0; iPost(); + } + + m_PingWhenIdle.clear(); +} + +void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt ) +{ + evt.Skip(); + m_PingTimer.Stop(); + PingDispatch( "Idle" ); +} + +void wxAppWithHelpers::OnPingTimeout( wxTimerEvent& evt ) +{ + PingDispatch( "Timeout" ); +} + +void wxAppWithHelpers::Ping() +{ + DbgCon.WriteLn( Color_Gray, L"App Event Ping Requested from %s thread.", pxGetCurrentThreadName().c_str() ); + + Semaphore sema; + pxPingEvent evt( &sema ); + AddPendingEvent( evt ); + sema.WaitNoCancel(); +} + +void wxAppWithHelpers::PostCommand( void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam ) +{ + wxCommandEvent evt( evtType ); + evt.SetClientData( clientData ); + evt.SetInt( intParam ); + evt.SetExtraLong( longParam ); + evt.SetString( stringParam ); + AddPendingEvent( evt ); +} + +void wxAppWithHelpers::PostCommand( int evtType, int intParam, long longParam, const wxString& stringParam ) +{ + PostCommand( NULL, evtType, intParam, longParam, stringParam ); +} + + +typedef void (wxEvtHandler::*pxMessageBoxEventFunction)(pxMessageBoxEvent&); +typedef void (wxEvtHandler::*pxPingEventFunction)(pxPingEvent&); + +bool wxAppWithHelpers::OnInit() +{ +#define pxMessageBoxEventThing(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxMessageBoxEventFunction, &func ) + +#define pxPingEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxPingEventFunction, &func ) + + Connect( pxEvt_MessageBox, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) ); + Connect( pxEvt_Assertion, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) ); + Connect( pxEvt_Ping, pxPingEventHandler (wxAppWithHelpers::OnPingEvent) ); + Connect( wxEvt_Idle, wxIdleEventHandler (wxAppWithHelpers::OnIdleEvent) ); + + Connect( m_PingTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnPingTimeout) ); + + return _parent::OnInit(); +} + +void wxAppWithHelpers::OnMessageBox( pxMessageBoxEvent& evt ) +{ + evt.IssueDialog(); +} + +wxAppWithHelpers::wxAppWithHelpers() + : m_PingTimer( this ) +{ +#ifdef __WXMSW__ + // This variable assignment ensures that MSVC links in the TLS setup stubs even in + // full optimization builds. Without it, DLLs that use TLS won't work because the + // FS segment register won't have been initialized by the main exe, due to tls_insurance + // being optimized away >_< --air + + static __threadlocal int tls_insurance = 0; + tls_insurance = 1; +#endif +} + diff --git a/pcsx2/gui/wxAppWithHelpers.h b/pcsx2/gui/wxAppWithHelpers.h new file mode 100644 index 0000000000..6df63ce54b --- /dev/null +++ b/pcsx2/gui/wxAppWithHelpers.h @@ -0,0 +1,302 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2009 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include + +#include "IniInterface.h" +#include "Utilities/Threading.h" +#include "Utilities/wxGuiTools.h" + +using namespace Threading; + +class pxPingEvent; +class pxMessageBoxEvent; + +BEGIN_DECLARE_EVENT_TYPES() + DECLARE_EVENT_TYPE( pxEvt_Ping, -1 ) + DECLARE_EVENT_TYPE( pxEvt_MessageBox, -1 ) + DECLARE_EVENT_TYPE( pxEvt_Assertion, -1 ) +END_DECLARE_EVENT_TYPES() + +// -------------------------------------------------------------------------------------- +// AppIniSaver / AppIniLoader +// -------------------------------------------------------------------------------------- +class AppIniSaver : public IniSaver +{ +public: + AppIniSaver(); + virtual ~AppIniSaver() throw() {} +}; + +class AppIniLoader : public IniLoader +{ +public: + AppIniLoader(); + virtual ~AppIniLoader() throw() {} +}; + +struct MsgboxEventResult +{ + Semaphore WaitForMe; + int result; + + MsgboxEventResult() + { + result = 0; + } +}; + +// -------------------------------------------------------------------------------------- +// MsgButtons +// -------------------------------------------------------------------------------------- +class MsgButtons +{ +protected: + BITFIELD32() + bool + m_OK :1, + m_Cancel :1, + m_Yes :1, + m_No :1, + m_AllowToAll:1, + m_Apply :1, + m_Abort :1, + m_Retry :1, + m_Ignore :1, + m_Reset :1, + m_Close :1; + BITFIELD_END + + wxString m_CustomLabel; + +public: + MsgButtons() : bitset( 0 ) { } + + MsgButtons& OK() { m_OK = true; return *this; } + MsgButtons& Cancel() { m_Cancel = true; return *this; } + MsgButtons& Apply() { m_Apply = true; return *this; } + MsgButtons& Yes() { m_Yes = true; return *this; } + MsgButtons& No() { m_No = true; return *this; } + MsgButtons& ToAll() { m_AllowToAll = true; return *this; } + + MsgButtons& Abort() { m_Abort = true; return *this; } + MsgButtons& Retry() { m_Retry = true; return *this; } + MsgButtons& Ignore() { m_Ignore = true; return *this; } + MsgButtons& Reset() { m_Reset = true; return *this; } + MsgButtons& Close() { m_Close = true; return *this; } + + MsgButtons& Custom( const wxString& label) + { + m_CustomLabel = label; + return *this; + } + + MsgButtons& OKCancel() { m_OK = m_Cancel = true; return *this; } + MsgButtons& YesNo() { m_Yes = m_No = true; return *this; } + + bool HasOK() const { return m_OK; } + bool HasCancel() const { return m_Cancel; } + bool HasApply() const { return m_Apply; } + bool HasYes() const { return m_Yes; } + bool HasNo() const { return m_No; } + bool AllowsToAll() const{ return m_AllowToAll; } + + bool HasAbort() const { return m_Abort; } + bool HasRetry() const { return m_Retry; } + bool HasIgnore() const { return m_Ignore; } + bool HasReset() const { return m_Reset; } + bool HasClose() const { return m_Close; } + + bool HasCustom() const { return !m_CustomLabel.IsEmpty(); } + const wxString& GetCustomLabel() const { return m_CustomLabel; } + + bool Allows( wxWindowID id ) const; + void SetBestFocus( wxWindow* dialog ) const; + void SetBestFocus( wxWindow& dialog ) const; + + bool operator ==( const MsgButtons& right ) const + { + return OpEqu( bitset ); + } + + bool operator !=( const MsgButtons& right ) const + { + return !OpEqu( bitset ); + } +}; + +// -------------------------------------------------------------------------------------- +// ModalButtonPanel +// -------------------------------------------------------------------------------------- +class ModalButtonPanel : public wxPanelWithHelpers +{ +public: + ModalButtonPanel( wxWindow* window, const MsgButtons& buttons ); + virtual ~ModalButtonPanel() throw() { } + + virtual void AddActionButton( wxWindowID id ); + virtual void AddCustomButton( wxWindowID id, const wxString& label ); + + virtual void OnActionButtonClicked( wxCommandEvent& evt ); +}; + +// -------------------------------------------------------------------------------------- +// BaseMessageBoxEvent +// -------------------------------------------------------------------------------------- +class BaseMessageBoxEvent : public wxEvent +{ + DECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent) + +protected: + MsgboxEventResult* m_Instdata; + wxString m_Content; + +public: + virtual ~BaseMessageBoxEvent() throw() { } + virtual BaseMessageBoxEvent *Clone() const { return new BaseMessageBoxEvent(*this); } + + explicit BaseMessageBoxEvent( int msgtype=pxEvt_MessageBox, const wxString& content=wxEmptyString ); + BaseMessageBoxEvent( MsgboxEventResult& instdata, const wxString& content ); + BaseMessageBoxEvent( const wxString& content ); + BaseMessageBoxEvent( const BaseMessageBoxEvent& event ); + + BaseMessageBoxEvent& SetInstData( MsgboxEventResult& instdata ); + + virtual void IssueDialog(); + +protected: + virtual int _DoDialog() const; +}; + +// -------------------------------------------------------------------------------------- +// pxMessageBoxEvent +// -------------------------------------------------------------------------------------- +// This event type is used to transfer message boxes to the main UI thread, and return the +// result of the box. It's the only way a message box can be issued from non-main threads +// with complete safety in wx2.8. +// +// For simplicity sake this message box only supports two basic designs. The main design +// is a generic message box with confirmation buttons of your choosing. Additionally you +// can specify a "scrollableContent" text string, which is added into a read-only richtext +// control similar to the console logs and such. +// +// Future consideration: If wxWidgets 3.0 has improved thread safety, then it should probably +// be reasonable for it to work with a more flexable model where the dialog can be created +// on a child thread, passed to the main thread, where ShowModal() is run (keeping the nested +// message pumps on the main thread where they belong). But so far this is not possible, +// because of various subtle issues in wx2.8 design. +// +class pxMessageBoxEvent : public BaseMessageBoxEvent +{ + typedef BaseMessageBoxEvent _parent; + DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent) + +protected: + wxString m_Title; + MsgButtons m_Buttons; + +public: + virtual ~pxMessageBoxEvent() throw() { } + virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); } + + explicit pxMessageBoxEvent( int msgtype=pxEvt_MessageBox ); + + pxMessageBoxEvent( MsgboxEventResult& instdata, const wxString& title, const wxString& content, const MsgButtons& buttons ); + pxMessageBoxEvent( const wxString& title, const wxString& content, const MsgButtons& buttons ); + pxMessageBoxEvent( const pxMessageBoxEvent& event ); + + pxMessageBoxEvent& SetInstData( MsgboxEventResult& instdata ); + +protected: + virtual int _DoDialog() const; +}; + +// -------------------------------------------------------------------------------------- +// pxAssertionEvent +// -------------------------------------------------------------------------------------- +class pxAssertionEvent : public BaseMessageBoxEvent +{ + typedef BaseMessageBoxEvent _parent; + DECLARE_DYNAMIC_CLASS_NO_ASSIGN( pxAssertionEvent ) + +protected: + wxString m_Stacktrace; + +public: + pxAssertionEvent(); + pxAssertionEvent( MsgboxEventResult& instdata, const wxString& content, const wxString& trace ); + pxAssertionEvent( const wxString& content, const wxString& trace ); + pxAssertionEvent( const pxAssertionEvent& event ); + + pxAssertionEvent& SetInstData( MsgboxEventResult& instdata ); + pxAssertionEvent& SetStacktrace( const wxString& trace ); + +protected: + virtual int _DoDialog() const; +}; + +// -------------------------------------------------------------------------------------- +// pxPingEvent +// -------------------------------------------------------------------------------------- +class pxPingEvent : public wxEvent +{ + DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxPingEvent) + +protected: + Semaphore* m_PostBack; + +public: + virtual ~pxPingEvent() throw() { } + virtual pxPingEvent *Clone() const { return new pxPingEvent(*this); } + + explicit pxPingEvent( int msgtype, Semaphore* sema=NULL ); + explicit pxPingEvent( Semaphore* sema=NULL ); + pxPingEvent( const pxPingEvent& src ); + + Semaphore* GetSemaphore() { return m_PostBack; } +}; + +// -------------------------------------------------------------------------------------- +// wxAppWithHelpers +// -------------------------------------------------------------------------------------- +class wxAppWithHelpers : public wxApp +{ + typedef wxApp _parent; + +protected: + std::vector m_PingWhenIdle; + wxTimer m_PingTimer; + +public: + wxAppWithHelpers(); + virtual ~wxAppWithHelpers() {} + + void PostCommand( void* clientData, int evtType, int intParam=0, long longParam=0, const wxString& stringParam=wxEmptyString ); + void PostCommand( int evtType, int intParam=0, long longParam=0, const wxString& stringParam=wxEmptyString ); + + void Ping(); + void PingDispatch( const char* action ); + + bool OnInit(); + //int OnExit(); + +protected: + void OnIdleEvent( wxIdleEvent& evt ); + void OnPingEvent( pxPingEvent& evt ); + void OnPingTimeout( wxTimerEvent& evt ); + void OnMessageBox( pxMessageBoxEvent& evt ); +}; diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 5fc2f39072..ccd8b7f123 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -1904,6 +1904,10 @@ RelativePath="..\..\gui\Saveslots.cpp" > + + @@ -2571,6 +2575,10 @@ RelativePath="..\..\gui\RecentIsoList.h" > + +