* 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:
Jake.Stine 2009-09-03 11:59:05 +00:00
parent ee97290cd2
commit 64e43a9086
19 changed files with 308 additions and 197 deletions

View File

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

View File

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

View File

@ -219,7 +219,7 @@ void mtgsThreadObject::Start()
mtgsThreadObject::~mtgsThreadObject()
{
Cancel();
mtgsThreadObject::Cancel();
}
void mtgsThreadObject::Cancel()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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