* 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
This commit is contained in:
Jake.Stine 2010-01-08 07:11:33 +00:00
parent 1298a35481
commit ac1df96678
25 changed files with 951 additions and 589 deletions

View File

@ -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))

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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." );
}

View File

@ -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;
};

View File

@ -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 );
}
};

View File

@ -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()

View File

@ -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:

View File

@ -15,32 +15,37 @@
#pragma once
#include <wx/wx.h>
#include "wxAppWithHelpers.h"
#include <wx/fileconf.h>
#include <wx/imaglist.h>
#include <wx/apptrait.h>
#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<AppEventType> m_evtsrc_AppStatus;
public:
CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; }
EventSource<int>& Source_SettingsApplied() { return m_evtsrc_SettingsApplied; }
EventSource<AppEventType>& Source_AppStatus() { return m_evtsrc_AppStatus; }
EventSource<PluginEventType>& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
EventSource<IniInterface>& Source_SettingsLoadSave() { return m_evtsrc_SettingsLoadSave; }
CmdEvt_Source& Source_CoreThreadStatus() { AffinityAssert_AllowFromMain(); return m_evtsrc_CoreThreadStatus; }
EventSource<int>& Source_SettingsApplied() { AffinityAssert_AllowFromMain(); return m_evtsrc_SettingsApplied; }
EventSource<AppEventType>& Source_AppStatus() { AffinityAssert_AllowFromMain(); return m_evtsrc_AppStatus; }
EventSource<PluginEventType>& Source_CorePluginStatus() { AffinityAssert_AllowFromMain(); return m_evtsrc_CorePluginStatus; }
EventSource<IniInterface>& Source_SettingsLoadSave() { AffinityAssert_AllowFromMain(); return m_evtsrc_SettingsLoadSave; }
// ----------------------------------------------------------------------------
public:
@ -370,16 +349,13 @@ protected:
GSFrame* m_gsFrame;
ConsoleLogFrame* m_ProgramLogBox;
std::vector<Semaphore*> 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

View File

@ -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,
};

View File

@ -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()

View File

@ -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()

View File

@ -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; i<size; ++i )
{
if( Semaphore* sema = m_PingWhenIdle[i] ) sema->Post();
}
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 )

View File

@ -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

View File

@ -47,7 +47,7 @@ void GSPanel::InitDefaultAccelerators()
GSPanel::GSPanel( wxWindow* parent )
: wxWindow()
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
, m_Listener_SettingsApplied ( wxGetApp().Source_SettingsApplied(), EventListener<int> ( 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 )

View File

@ -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 )

View File

@ -99,7 +99,7 @@ public:
class IniLoader : public IniInterface
{
public:
virtual ~IniLoader();
virtual ~IniLoader() throw();
explicit IniLoader();
explicit IniLoader( wxConfigBase& config );

View File

@ -67,6 +67,8 @@ protected:
// --------------------------------------------------------------------------------------
class GSFrame : public wxFrame
{
typedef wxFrame _parent;
protected:
EventListenerBinding<int> 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 );

View File

@ -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)

View File

@ -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();
}

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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; i<size; ++i )
{
if( Semaphore* sema = m_PingWhenIdle[i] ) sema->Post();
}
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
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <wx/wx.h>
#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<Semaphore*> 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 );
};

View File

@ -1904,6 +1904,10 @@
RelativePath="..\..\gui\Saveslots.cpp"
>
</File>
<File
RelativePath="..\..\gui\wxAppWithHelpers.cpp"
>
</File>
<Filter
Name="Dialogs"
>
@ -2571,6 +2575,10 @@
RelativePath="..\..\gui\RecentIsoList.h"
>
</File>
<File
RelativePath="..\..\gui\wxAppWithHelpers.h"
>
</File>
</Filter>
<Filter
Name="Win32"