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