mirror of https://github.com/PCSX2/pcsx2.git
User Interface code cleanups and bugfixes. some highlights:
* Configuration panels are all modal-less now, so that you can open the config panel and leave it open while running games. * Handful of thread sync improvements. * Fixed on-the-fly interpreter/recompiler configuration. * Fixed plugin hotswapping (mostly works, but still a little funny at times) * All new assertion dialogs and popup message handlers. * RecentIsoList defaults to 12 instead of 6 Dev Notes: * I had to create a new set of assertion functions called pxAssume*. Originally I hoped to avoid that complexity, and just use a single one-assert-fits-all case, but turned out blanketly using __assume() for all assertion cases wasn't reliable. * wxGuiTools: Replaced the operator, with operator& -- the latter has proper order of precedence, the former required () to scope correctly. >_< git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2339 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
cc65a5cd02
commit
c17455c702
|
@ -126,6 +126,13 @@
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PCSX2_DEBUG
|
||||||
|
# define pxDebugCode(code) code
|
||||||
|
#else
|
||||||
|
# define pxDebugCode(code)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// __aligned / __aligned16 / __pagealigned
|
// __aligned / __aligned16 / __pagealigned
|
||||||
//
|
//
|
||||||
|
@ -201,8 +208,8 @@ static const int __pagesize = PCSX2_PAGESIZE;
|
||||||
// Don't know if there are Visual C++ equivalents of these.
|
// Don't know if there are Visual C++ equivalents of these.
|
||||||
# define __hot
|
# define __hot
|
||||||
# define __cold
|
# define __cold
|
||||||
# define likely(x) x
|
# define likely(x) (!!(x))
|
||||||
# define unlikely(x) x
|
# define unlikely(x) (!!(x))
|
||||||
|
|
||||||
# define CALLBACK __stdcall
|
# define CALLBACK __stdcall
|
||||||
|
|
||||||
|
|
|
@ -15,60 +15,136 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __pxFUNCTION__
|
||||||
|
#if defined(__GNUG__)
|
||||||
|
# define __pxFUNCTION__ __PRETTY_FUNCTION__
|
||||||
|
#else
|
||||||
|
# define __pxFUNCTION__ __FUNCTION__
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef wxNullChar
|
||||||
|
# define wxNullChar ((wxChar*)NULL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// FnChar_t - function name char type; typedef'd in case it ever changes between compilers
|
||||||
|
// (ie, a compiler decides to wchar_t it instead of char/UTF8).
|
||||||
|
typedef char FnChar_t;
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// DiagnosticOrigin
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
struct DiagnosticOrigin
|
||||||
|
{
|
||||||
|
const wxChar* srcfile;
|
||||||
|
const FnChar_t* function;
|
||||||
|
const wxChar* condition;
|
||||||
|
int line;
|
||||||
|
|
||||||
|
DiagnosticOrigin( const wxChar *_file, int _line, const FnChar_t *_func, const wxChar* _cond = NULL )
|
||||||
|
: srcfile( _file )
|
||||||
|
, function( _func )
|
||||||
|
, condition( _cond )
|
||||||
|
, line( _line )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString ToString( const wxChar* msg=NULL ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns ture if the assertion is to trap into the debugger, or false if execution
|
||||||
|
// of the program should continue unimpeded.
|
||||||
|
typedef bool pxDoAssertFnType(const DiagnosticOrigin& origin, const wxChar *msg);
|
||||||
|
|
||||||
|
extern pxDoAssertFnType pxAssertImpl_LogIt;
|
||||||
|
|
||||||
|
extern pxDoAssertFnType* pxDoAssert;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
// pxAssert / pxAssertDev / pxFail / pxFailDev
|
// pxAssert / pxAssertDev
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
// Standard "nothrow" assertions. All assertions act as valid conditional statements that
|
// Standard "nothrow" assertions. All assertions act as valid conditional statements that
|
||||||
// return the result of the specified conditional; useful for handling failed assertions in
|
// return the result of the specified conditional; useful for handling failed assertions in
|
||||||
// a "graceful" fashion when utilizing the "ignore" feature of assertion debugging.
|
// a "graceful" fashion when utilizing the "ignore" feature of assertion debugging.
|
||||||
|
// These macros are mostly intended for "pseudo-weak" assumptions within code, most often for
|
||||||
|
// testing threaded user interface code (threading of the UI is a prime example since often
|
||||||
|
// even very robust assertions can fail in very rare conditions, due to the complex variety
|
||||||
|
// of ways the user can invoke UI events).
|
||||||
//
|
//
|
||||||
// Performance: All assertion types optimize into __assume()/likely() directives in Release
|
// All macros return TRUE if the assertion succeeds, or FALSE if the assertion failed
|
||||||
// builds. If using assertions as part of a conditional, the conditional code *will* not
|
// (thus matching the condition of the assertion itself).
|
||||||
// be optimized out, so use conditionals with caution.
|
|
||||||
//
|
//
|
||||||
// pxAssertDev is an assertion tool for Devel builds, intended for sanity checking and/or
|
// pxAssertDev is an assertion tool for Devel builds, intended for sanity checking and/or
|
||||||
// bounds checking variables in areas which are not performance critical. Another common
|
// bounds checking variables in areas which are not performance critical. Another common
|
||||||
// use is for checking thread affinity on utility functions.
|
// use is for checking thread affinity on utility functions.
|
||||||
//
|
//
|
||||||
// Credits Notes: These macros are based on a combination of wxASSERT, MSVCRT's assert
|
// Credits: These macros are based on a combination of wxASSERT, MSVCRT's assert and the
|
||||||
// and the ATL's Assertion/Assumption macros. the best of all worlds!
|
// ATL's Assertion/Assumption macros. the best of all worlds!
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// pxAssume / pxAssumeDev / pxFail / pxFailDev
|
||||||
|
// --------------------------------------------------------------------------------------
|
||||||
|
// Assumptions are like "extra rigid" assertions, which should never fail under any circum-
|
||||||
|
// stance in release build optimized code.
|
||||||
|
//
|
||||||
|
// Performance: All assumption/fail types optimize into __assume()/likely() directives in
|
||||||
|
// Release builds (non-dev varieties optimize as such in Devel builds as well). If using
|
||||||
|
|
||||||
|
#define pxDiagSpot DiagnosticOrigin( __TFILE__, __LINE__, __pxFUNCTION__ )
|
||||||
|
#define pxAssertSpot(cond) DiagnosticOrigin( __TFILE__, __LINE__, __pxFUNCTION__, _T(#cond) )
|
||||||
|
|
||||||
|
// pxAssertRel ->
|
||||||
|
// Special release-mode assertion. Limited use since stack traces in release mode builds
|
||||||
|
// (especially with LTCG) are highly suspect. But when troubleshooting crashes that only
|
||||||
|
// rear ugly heads in optimized builds, this is one of the few tools we have.
|
||||||
|
|
||||||
|
#define pxAssertRel(cond, msg) ( (likely(cond)) || (pxOnAssert(pxAssertSpot(cond), msg), false) )
|
||||||
|
#define pxAssumeMsg(cond, msg) ((void) ( (!likely(cond)) && (pxOnAssert(pxAssertSpot(cond), msg), false) ))
|
||||||
|
|
||||||
#if defined(PCSX2_DEBUG)
|
#if defined(PCSX2_DEBUG)
|
||||||
|
|
||||||
# define pxAssertMsg(cond, msg) ( (!!(cond)) || \
|
# define pxAssertMsg(cond, msg) pxAssertRel(cond, msg)
|
||||||
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), likely(cond)) )
|
# define pxAssertDev(cond, msg) pxAssertMsg(cond, msg)
|
||||||
|
|
||||||
# define pxAssertDev(cond,msg) pxAssertMsg(cond, msg)
|
# define pxAssume(cond) pxAssumeMsg(cond, wxNullChar)
|
||||||
|
# define pxAssumeDev(cond, msg) pxAssumeMsg(cond, msg)
|
||||||
|
|
||||||
# define pxFail(msg) pxAssertMsg(false, msg)
|
# define pxFail(msg) pxAssumeMsg(false, msg)
|
||||||
# define pxFailDev(msg) pxAssertDev(false, msg)
|
# define pxFailDev(msg) pxAssumeDev(false, msg)
|
||||||
|
|
||||||
#elif defined(PCSX2_DEVBUILD)
|
#elif defined(PCSX2_DEVBUILD)
|
||||||
|
|
||||||
// Devel builds use __assume for standard assertions and call pxOnAssertDevel
|
// Devel builds use __assume for standard assertions and call pxOnAssertDevel
|
||||||
// for AssertDev brand assertions (which typically throws a LogicError exception).
|
// for AssertDev brand assertions (which typically throws a LogicError exception).
|
||||||
|
|
||||||
# define pxAssertMsg(cond, msg) (__assume(cond), likely(cond))
|
# define pxAssertMsg(cond, msg) (likely(cond))
|
||||||
|
# define pxAssertDev(cond, msg) pxAssertRel(cond, msg)
|
||||||
|
|
||||||
# define pxAssertDev(cond, msg) ( (!!(cond)) || \
|
# define pxAssume(cond) (__assume(cond))
|
||||||
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), likely(cond)) )
|
# define pxAssumeDev(cond, msg) pxAssumeMsg(cond, msg)
|
||||||
|
|
||||||
# define pxFail(msg) (__assume(false), false)
|
# define pxFail(msg) (__assume(false))
|
||||||
# define pxFailDev(msg ) pxAssertDev(false, msg)
|
# define pxFailDev(msg) pxAssumeDev(false, msg)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Release Builds just use __assume as an optimization, and return the conditional
|
// Release Builds just use __assume as an optimization, and return the conditional
|
||||||
// as a result (which is optimized to nil if unused).
|
// as a result (which is optimized to nil if unused).
|
||||||
|
|
||||||
# define pxAssertMsg(cond, msg) (__assume(cond), likely(cond))
|
# define pxAssertMsg(cond, msg) (likely(cond))
|
||||||
# define pxAssertDev(cond, msg) (__assume(cond), likely(cond))
|
# define pxAssertDev(cond, msg) (likely(cond))
|
||||||
# define pxFail(msg) (__assume(false), false)
|
|
||||||
# define pxFailDev(msg) (__assume(false), false)
|
# define pxAssume(cond) (__assume(cond))
|
||||||
|
# define pxAssumeDev(cond, msg) (__assume(cond))
|
||||||
|
|
||||||
|
# define pxFail(msg) (__assume(false))
|
||||||
|
# define pxFailDev(msg) (__assume(false))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define pxAssert(cond) pxAssertMsg(cond, (wxChar*)NULL)
|
#define pxAssert(cond) pxAssertMsg(cond, wxNullChar)
|
||||||
|
|
||||||
|
#define pxAssertRelease( cond, msg )
|
||||||
|
|
||||||
// Performs an unsigned index bounds check, and generates a debug assertion if the check fails.
|
// Performs an unsigned index bounds check, and generates a debug assertion if the check fails.
|
||||||
// For stricter checking in Devel builds as well as debug builds (but possibly slower), use
|
// For stricter checking in Devel builds as well as debug builds (but possibly slower), use
|
||||||
|
@ -81,8 +157,8 @@
|
||||||
wxsFormat( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) )
|
wxsFormat( L"Array index out of bounds accessing object '%s' (index=%d, size=%d)", objname, (idx), (sze) ) )
|
||||||
|
|
||||||
|
|
||||||
extern void pxOnAssert( const wxChar* file, int line, const char* func, const wxChar* cond, const wxChar* msg);
|
extern void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg=NULL );
|
||||||
extern void pxOnAssert( const wxChar* file, int line, const char* func, const wxChar* cond, const char* msg);
|
extern void pxOnAssert( const DiagnosticOrigin& origin, const char* msg );
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// jNO_DEFAULT -- disables the default case in a switch, which improves switch optimization
|
// jNO_DEFAULT -- disables the default case in a switch, which improves switch optimization
|
||||||
|
@ -92,29 +168,23 @@ extern void pxOnAssert( const wxChar* file, int line, const char* func, const wx
|
||||||
// in the 'default:' case of a switch tells the compiler that the case is unreachable, so
|
// in the 'default:' case of a switch tells the compiler that the case is unreachable, so
|
||||||
// that it will not generate any code, LUTs, or conditionals to handle it.
|
// that it will not generate any code, LUTs, or conditionals to handle it.
|
||||||
//
|
//
|
||||||
// * In debug builds the default case will cause an assertion.
|
// * In debug/devel builds the default case will cause an assertion.
|
||||||
// * In devel builds the default case will cause a LogicError exception (C++ only)
|
|
||||||
// (either meaning the jNO_DEFAULT has been used incorrectly, and that the default case is in
|
|
||||||
// fact used and needs to be handled).
|
|
||||||
//
|
|
||||||
// MSVC Note: To stacktrace LogicError exceptions, add Exception::LogicError to the C++ First-
|
|
||||||
// Chance Exception list (under Debug->Exceptions menu).
|
|
||||||
//
|
//
|
||||||
#ifndef jNO_DEFAULT
|
#ifndef jNO_DEFAULT
|
||||||
|
|
||||||
#if defined(__cplusplus) && defined(PCSX2_DEVBUILD)
|
#if defined(__cplusplus) && defined(PCSX2_DEVBUILD)
|
||||||
# define jNO_DEFAULT \
|
# define jNO_DEFAULT \
|
||||||
default: \
|
default: \
|
||||||
{ \
|
{ \
|
||||||
pxFailDev( "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)" ); \
|
pxFailDev( "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)" ); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define jNO_DEFAULT \
|
# define jNO_DEFAULT \
|
||||||
default: \
|
default: \
|
||||||
{ \
|
{ \
|
||||||
jASSUME(0); \
|
jASSUME(0); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,11 +38,7 @@
|
||||||
Console.Error( ex.what() ); \
|
Console.Error( ex.what() ); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __GNUG__
|
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL( __pxFUNCTION__ )
|
||||||
# define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL( __PRETTY_FUNCTION__ )
|
|
||||||
#else
|
|
||||||
# define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL( __FUNCTION__ )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
{
|
{
|
||||||
|
@ -56,7 +52,7 @@ namespace Exception
|
||||||
// catch clause can optionally modify them and then re-throw to a top-level handler.
|
// catch clause can optionally modify them and then re-throw to a top-level handler.
|
||||||
//
|
//
|
||||||
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
|
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
|
||||||
// Use Exception::RuntimeError or Exception::LogicError instead for generic exceptions.
|
// Use Exception::RuntimeError instead for generic exceptions.
|
||||||
//
|
//
|
||||||
// Because exceptions are the (only!) really useful example of multiple inheritance,
|
// Because exceptions are the (only!) really useful example of multiple inheritance,
|
||||||
// this class has only a trivial constructor, and must be manually initialized using
|
// this class has only a trivial constructor, and must be manually initialized using
|
||||||
|
@ -150,7 +146,7 @@ namespace Exception
|
||||||
explicit classname( const wxString& msg_eng ) { BaseException::InitBaseEx( msg_eng, wxEmptyString ); }
|
explicit classname( const wxString& msg_eng ) { BaseException::InitBaseEx( msg_eng, wxEmptyString ); }
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// RuntimeError / LogicError - Generalized Exceptions
|
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class RuntimeError : public virtual BaseException
|
class RuntimeError : public virtual BaseException
|
||||||
|
@ -161,14 +157,6 @@ namespace Exception
|
||||||
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
|
DEFINE_RUNTIME_EXCEPTION( RuntimeError, wxLt("An unhandled runtime error has occurred, somewhere in the depths of Pcsx2's cluttered brain-matter.") )
|
||||||
};
|
};
|
||||||
|
|
||||||
// LogicErrors do not need translated versions, since they are typically obscure, and the
|
|
||||||
// user wouldn't benefit from being able to understand them anyway. :)
|
|
||||||
class LogicError : public virtual BaseException
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DEFINE_LOGIC_EXCEPTION( LogicError, wxLt("An unhandled logic error has occurred.") )
|
|
||||||
};
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
|
// CancelAppEvent - Exception for canceling an event in a non-verbose fashion
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -227,24 +215,6 @@ namespace Exception
|
||||||
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, wxLt("Out of Memory") )
|
DEFINE_RUNTIME_EXCEPTION( OutOfMemory, wxLt("Out of Memory") )
|
||||||
};
|
};
|
||||||
|
|
||||||
// This exception thrown any time an operation is attempted when an object
|
|
||||||
// is in an uninitialized state.
|
|
||||||
//
|
|
||||||
class InvalidOperation : public virtual LogicError
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DEFINE_LOGIC_EXCEPTION( InvalidOperation, "Attempted method call is invalid for the current object or program state." )
|
|
||||||
};
|
|
||||||
|
|
||||||
// This exception thrown any time an operation is attempted when an object
|
|
||||||
// is in an uninitialized state.
|
|
||||||
//
|
|
||||||
class InvalidArgument : public virtual LogicError
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DEFINE_LOGIC_EXCEPTION( InvalidArgument, "Invalid argument passed to a function." )
|
|
||||||
};
|
|
||||||
|
|
||||||
class ParseError : public RuntimeError
|
class ParseError : public RuntimeError
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -32,6 +32,9 @@ class wxTimeSpan;
|
||||||
namespace Threading
|
namespace Threading
|
||||||
{
|
{
|
||||||
class PersistentThread;
|
class PersistentThread;
|
||||||
|
|
||||||
|
PersistentThread* pxGetCurrentThread();
|
||||||
|
wxString pxGetCurrentThreadName();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Exception
|
namespace Exception
|
||||||
|
@ -346,12 +349,11 @@ namespace Threading
|
||||||
DeclareNoncopyableObject(PersistentThread);
|
DeclareNoncopyableObject(PersistentThread);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef int (*PlainJoeFP)();
|
|
||||||
|
|
||||||
wxString m_name; // diagnostic name for our thread.
|
wxString m_name; // diagnostic name for our thread.
|
||||||
|
|
||||||
pthread_t m_thread;
|
pthread_t m_thread;
|
||||||
Semaphore m_sem_event; // general wait event that's needed by most threads.
|
Semaphore m_sem_event; // general wait event that's needed by most threads
|
||||||
|
Semaphore m_sem_startup; // startup sync tool
|
||||||
Mutex m_lock_InThread; // used for canceling and closing threads in a deadlock-safe manner
|
Mutex m_lock_InThread; // used for canceling and closing threads in a deadlock-safe manner
|
||||||
MutexLockRecursive m_lock_start; // used to lock the Start() code from starting simultaneous threads accidentally.
|
MutexLockRecursive m_lock_start; // used to lock the Start() code from starting simultaneous threads accidentally.
|
||||||
|
|
||||||
|
@ -369,6 +371,7 @@ namespace Threading
|
||||||
|
|
||||||
virtual void Start();
|
virtual void Start();
|
||||||
virtual void Cancel( bool isBlocking = true );
|
virtual void Cancel( bool isBlocking = true );
|
||||||
|
virtual bool Cancel( const wxTimeSpan& timeout );
|
||||||
virtual bool Detach();
|
virtual bool Detach();
|
||||||
virtual void Block();
|
virtual void Block();
|
||||||
virtual void RethrowException() const;
|
virtual void RethrowException() const;
|
||||||
|
@ -419,12 +422,13 @@ namespace Threading
|
||||||
|
|
||||||
void FrankenMutex( Mutex& mutex );
|
void FrankenMutex( Mutex& mutex );
|
||||||
|
|
||||||
bool AffinityAssert_AllowFromSelf() const;
|
bool AffinityAssert_AllowFromSelf( const DiagnosticOrigin& origin ) const;
|
||||||
bool AffinityAssert_DisallowFromSelf() const;
|
bool AffinityAssert_DisallowFromSelf( const DiagnosticOrigin& origin ) const;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Section of methods for internal use only.
|
// Section of methods for internal use only.
|
||||||
|
|
||||||
|
bool _basecancel();
|
||||||
void _selfRunningTest( const wxChar* name ) const;
|
void _selfRunningTest( const wxChar* name ) const;
|
||||||
void _DoSetThreadName( const wxString& name );
|
void _DoSetThreadName( const wxString& name );
|
||||||
void _DoSetThreadName( const char* name );
|
void _DoSetThreadName( const char* name );
|
||||||
|
|
|
@ -58,9 +58,16 @@ protected:
|
||||||
|
|
||||||
extern void operator+=( wxSizer& target, pxCheckBox* src );
|
extern void operator+=( wxSizer& target, pxCheckBox* src );
|
||||||
extern void operator+=( wxSizer& target, pxCheckBox& src );
|
extern void operator+=( wxSizer& target, pxCheckBox& src );
|
||||||
|
extern void operator+=( wxSizer* target, pxCheckBox& src );
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void operator+=( wxSizer& target, const pxWindowAndFlags<pxCheckBox>& src )
|
inline void operator+=( wxSizer& target, const pxWindowAndFlags<pxCheckBox>& src )
|
||||||
{
|
{
|
||||||
target.Add( src.window, src.flags );
|
target.Add( src.window, src.flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void operator+=( wxSizer* target, const pxWindowAndFlags<pxCheckBox>& src )
|
||||||
|
{
|
||||||
|
target->Add( src.window, src.flags );
|
||||||
|
}
|
||||||
|
|
|
@ -111,7 +111,8 @@ public:
|
||||||
|
|
||||||
pxRadioPanel& SetToolTip( int idx, const wxString& tip );
|
pxRadioPanel& SetToolTip( int idx, const wxString& tip );
|
||||||
pxRadioPanel& SetSelection( int idx );
|
pxRadioPanel& SetSelection( int idx );
|
||||||
pxRadioPanel& SetDefault( int idx );
|
pxRadioPanel& SetDefaultItem( int idx );
|
||||||
|
pxRadioPanel& EnableItem( int idx, bool enable=true );
|
||||||
|
|
||||||
int GetSelection() const;
|
int GetSelection() const;
|
||||||
wxWindowID GetSelectionId() const;
|
wxWindowID GetSelectionId() const;
|
||||||
|
|
|
@ -86,6 +86,7 @@ protected:
|
||||||
|
|
||||||
extern void operator+=( wxSizer& target, pxStaticText* src );
|
extern void operator+=( wxSizer& target, pxStaticText* src );
|
||||||
extern void operator+=( wxSizer& target, pxStaticText& src );
|
extern void operator+=( wxSizer& target, pxStaticText& src );
|
||||||
|
extern void operator+=( wxSizer* target, pxStaticText& src );
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void operator+=( wxSizer& target, const pxWindowAndFlags<pxStaticText>& src )
|
inline void operator+=( wxSizer& target, const pxWindowAndFlags<pxStaticText>& src )
|
||||||
|
@ -94,6 +95,13 @@ inline void operator+=( wxSizer& target, const pxWindowAndFlags<pxStaticText>& s
|
||||||
//target.Add( src.window, src.flags );
|
//target.Add( src.window, src.flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void operator+=( wxSizer* target, const pxWindowAndFlags<pxStaticText>& src )
|
||||||
|
{
|
||||||
|
src.window->AddTo( target, src.flags );
|
||||||
|
//target.Add( src.window, src.flags );
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// pxStaticHeading
|
// pxStaticHeading
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -52,15 +52,25 @@ struct pxAlignmentType
|
||||||
|
|
||||||
wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const;
|
wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const;
|
||||||
|
|
||||||
|
wxSizerFlags operator& ( const wxSizerFlags& _flgs ) const
|
||||||
|
{
|
||||||
|
return Apply( _flgs );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSizerFlags Border( int dir, int padding ) const
|
||||||
|
{
|
||||||
|
return Apply().Border( dir, padding );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSizerFlags Proportion( int prop ) const
|
||||||
|
{
|
||||||
|
return Apply().Proportion( intval );
|
||||||
|
}
|
||||||
|
|
||||||
operator wxSizerFlags() const
|
operator wxSizerFlags() const
|
||||||
{
|
{
|
||||||
return Apply();
|
return Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizerFlags operator | ( const wxSizerFlags& _flgs )
|
|
||||||
{
|
|
||||||
return Apply( _flgs );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pxStretchType
|
struct pxStretchType
|
||||||
|
@ -78,15 +88,47 @@ struct pxStretchType
|
||||||
|
|
||||||
wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const;
|
wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const;
|
||||||
|
|
||||||
|
wxSizerFlags operator& ( const wxSizerFlags& _flgs ) const
|
||||||
|
{
|
||||||
|
return Apply( _flgs );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSizerFlags Border( int dir, int padding ) const
|
||||||
|
{
|
||||||
|
return Apply().Border( dir, padding );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSizerFlags Proportion( int prop ) const
|
||||||
|
{
|
||||||
|
return Apply().Proportion( intval );
|
||||||
|
}
|
||||||
|
|
||||||
operator wxSizerFlags() const
|
operator wxSizerFlags() const
|
||||||
{
|
{
|
||||||
return Apply();
|
return Apply();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
wxSizerFlags operator | ( const wxSizerFlags& _flgs )
|
class pxProportion
|
||||||
|
{
|
||||||
|
int intval;
|
||||||
|
|
||||||
|
pxProportion( int prop )
|
||||||
|
{
|
||||||
|
intval = prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSizerFlags Apply( wxSizerFlags flags=wxSizerFlags() ) const;
|
||||||
|
|
||||||
|
wxSizerFlags operator& ( const wxSizerFlags& _flgs ) const
|
||||||
{
|
{
|
||||||
return Apply( _flgs );
|
return Apply( _flgs );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator wxSizerFlags() const
|
||||||
|
{
|
||||||
|
return Apply();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const pxAlignmentType
|
extern const pxAlignmentType
|
||||||
|
@ -128,8 +170,7 @@ struct pxWindowAndFlags
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern wxSizerFlags operator , ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 ); //pxAlignmentType align );
|
extern wxSizerFlags operator& ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 );
|
||||||
//extern wxSizerFlags operator , ( const wxSizerFlags& _flgs, pxStretchType stretch );
|
|
||||||
|
|
||||||
template< typename WinType >
|
template< typename WinType >
|
||||||
pxWindowAndFlags<WinType> operator | ( WinType* _win, const wxSizerFlags& _flgs )
|
pxWindowAndFlags<WinType> operator | ( WinType* _win, const wxSizerFlags& _flgs )
|
||||||
|
@ -162,9 +203,13 @@ extern void operator+=( wxSizer& target, wxSizer* src );
|
||||||
extern void operator+=( wxSizer& target, wxWindow& src );
|
extern void operator+=( wxSizer& target, wxWindow& src );
|
||||||
extern void operator+=( wxSizer& target, wxSizer& src );
|
extern void operator+=( wxSizer& target, wxSizer& src );
|
||||||
|
|
||||||
|
extern void operator+=( wxSizer* target, wxWindow& src );
|
||||||
|
extern void operator+=( wxSizer* target, wxSizer& src );
|
||||||
|
|
||||||
extern void operator+=( wxSizer& target, int spacer );
|
extern void operator+=( wxSizer& target, int spacer );
|
||||||
extern void operator+=( wxWindow& target, int spacer );
|
extern void operator+=( wxWindow& target, int spacer );
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
// Important: This template is needed in order to retain window type information and
|
// Important: This template is needed in order to retain window type information and
|
||||||
// invoke the proper overloaded version of += (which is used by pxStaticText and other
|
// invoke the proper overloaded version of += (which is used by pxStaticText and other
|
||||||
// classes to perform special actions when added to sizers).
|
// classes to perform special actions when added to sizers).
|
||||||
|
@ -178,6 +223,14 @@ void operator+=( wxWindow& target, WinType* src )
|
||||||
template< typename WinType >
|
template< typename WinType >
|
||||||
void operator+=( wxWindow& target, WinType& src )
|
void operator+=( wxWindow& target, WinType& src )
|
||||||
{
|
{
|
||||||
|
if( !pxAssert( target.GetSizer() != NULL ) ) return;
|
||||||
|
*target.GetSizer() += src;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename WinType >
|
||||||
|
void operator+=( wxWindow& target, const pxWindowAndFlags<WinType>& src )
|
||||||
|
{
|
||||||
|
if( !pxAssert( target.GetSizer() != NULL ) ) return;
|
||||||
*target.GetSizer() += src;
|
*target.GetSizer() += src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,11 +240,31 @@ void operator+=( wxSizer& target, const pxWindowAndFlags<WinType>& src )
|
||||||
target.Add( src.window, src.flags );
|
target.Add( src.window, src.flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Pointer Versions! (note that C++ requires one of the two operator params be a
|
||||||
|
// "poper" object type (non-pointer), so that's why some of these are missing.
|
||||||
|
|
||||||
template< typename WinType >
|
template< typename WinType >
|
||||||
void operator+=( wxWindow& target, const pxWindowAndFlags<WinType>& src )
|
void operator+=( wxWindow* target, WinType& src )
|
||||||
{
|
{
|
||||||
if( !pxAssert( target.GetSizer() != NULL ) ) return;
|
if( !pxAssert( target != NULL ) ) return;
|
||||||
*target.GetSizer() += src;
|
if( !pxAssert( target->GetSizer() != NULL ) ) return;
|
||||||
|
*target->GetSizer() += src;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename WinType >
|
||||||
|
void operator+=( wxWindow* target, const pxWindowAndFlags<WinType>& src )
|
||||||
|
{
|
||||||
|
if( !pxAssert( target != NULL ) ) return;
|
||||||
|
if( !pxAssert( target->GetSizer() != NULL ) ) return;
|
||||||
|
*target->GetSizer() += src;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename WinType >
|
||||||
|
void operator+=( wxSizer* target, const pxWindowAndFlags<WinType>& src )
|
||||||
|
{
|
||||||
|
if( !pxAssert( target != NULL ) ) return;
|
||||||
|
target.Add( src.window, src.flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -230,19 +303,29 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wxDialogWithHelpers();
|
wxDialogWithHelpers();
|
||||||
wxDialogWithHelpers(wxWindow* parent, int id, const wxString& title, bool hasContextHelp, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize );
|
wxDialogWithHelpers(wxWindow* parent, const wxString& title, bool hasContextHelp=false, bool resizable=false );
|
||||||
|
wxDialogWithHelpers(wxWindow* parent, const wxString& title, wxOrientation orient);
|
||||||
virtual ~wxDialogWithHelpers() throw();
|
virtual ~wxDialogWithHelpers() throw();
|
||||||
|
|
||||||
void AddOkCancel( wxSizer& sizer, bool hasApply=false );
|
void Init();
|
||||||
pxStaticText* Text( const wxString& label );
|
void AddOkCancel( wxSizer& sizer, bool hasApply=false );
|
||||||
pxStaticHeading* Heading( const wxString& label );
|
|
||||||
|
virtual void SmartCenterFit();
|
||||||
|
virtual int ShowModal();
|
||||||
|
virtual bool Show( bool show=true );
|
||||||
|
|
||||||
|
virtual pxStaticText* Text( const wxString& label );
|
||||||
|
virtual pxStaticHeading* Heading( const wxString& label );
|
||||||
|
|
||||||
|
virtual wxDialogWithHelpers& SetIdealWidth( int newWidth ) { m_idealWidth = newWidth; return *this; }
|
||||||
|
|
||||||
wxDialogWithHelpers& SetIdealWidth( int newWidth ) { m_idealWidth = newWidth; return *this; }
|
|
||||||
int GetIdealWidth() const { return m_idealWidth; }
|
int GetIdealWidth() const { return m_idealWidth; }
|
||||||
bool HasIdealWidth() const { return m_idealWidth != wxDefaultCoord; }
|
bool HasIdealWidth() const { return m_idealWidth != wxDefaultCoord; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnActivate(wxActivateEvent& evt);
|
void OnActivate(wxActivateEvent& evt);
|
||||||
|
void OnOkCancel(wxCommandEvent& evt);
|
||||||
|
void OnCloseWindow(wxCloseEvent& event);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -412,7 +495,7 @@ public:
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
extern bool pxDialogExists( wxWindowID id );
|
extern bool pxDialogExists( const wxString& name );
|
||||||
extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos );
|
extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos );
|
||||||
extern wxRect wxGetDisplayArea();
|
extern wxRect wxGetDisplayArea();
|
||||||
|
|
||||||
|
@ -420,5 +503,7 @@ extern wxString pxFormatToolTipText( wxWindow* wind, const wxString& src );
|
||||||
extern void pxSetToolTip( wxWindow* wind, const wxString& src );
|
extern void pxSetToolTip( wxWindow* wind, const wxString& src );
|
||||||
extern void pxSetToolTip( wxWindow& wind, const wxString& src );
|
extern void pxSetToolTip( wxWindow& wind, const wxString& src );
|
||||||
|
|
||||||
|
extern wxFont pxGetFixedFont( int ptsize=8, int weight=wxNORMAL );
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct x86CPU_INFO
|
||||||
u32 PhysicalCores;
|
u32 PhysicalCores;
|
||||||
u32 LogicalCores;
|
u32 LogicalCores;
|
||||||
|
|
||||||
char VendorName[16]; // Vendor/Creator ID
|
char VendorName[16]; // Vendor/Creator ID
|
||||||
char TypeName[20]; // cpu type
|
char TypeName[20]; // cpu type
|
||||||
char FamilyName[50]; // the original cpu name
|
char FamilyName[50]; // the original cpu name
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#include <wx/app.h>
|
#include <wx/app.h>
|
||||||
|
#include "Threading.h"
|
||||||
|
|
||||||
wxString GetEnglish( const char* msg )
|
wxString GetEnglish( const char* msg )
|
||||||
{
|
{
|
||||||
|
@ -42,36 +43,66 @@ wxString GetTranslation( const char* msg )
|
||||||
// That's ok. What we don't want is the *same* thread recurse-asserting.
|
// That's ok. What we don't want is the *same* thread recurse-asserting.
|
||||||
static __threadlocal int s_assert_guard = 0;
|
static __threadlocal int s_assert_guard = 0;
|
||||||
|
|
||||||
DEVASSERT_INLINE void pxOnAssert( const wxChar* file, int line, const char* func, const wxChar* cond, const wxChar* msg)
|
pxDoAssertFnType* pxDoAssert = pxAssertImpl_LogIt;
|
||||||
{
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
|
||||||
RecursionGuard guard( s_assert_guard );
|
|
||||||
if( guard.IsReentrant() ) return;
|
|
||||||
|
|
||||||
if( wxTheApp == NULL )
|
// make life easier for people using VC++ IDE by using this format, which allows double-click
|
||||||
|
// response times from the Output window...
|
||||||
|
wxString DiagnosticOrigin::ToString( const wxChar* msg ) const
|
||||||
|
{
|
||||||
|
wxString message;
|
||||||
|
message.reserve( 2048 );
|
||||||
|
|
||||||
|
message.Printf( L"%s(%d) : assertion failed:\n", srcfile, line );
|
||||||
|
|
||||||
|
if( function != NULL )
|
||||||
|
message += L" Function: " + fromUTF8(function) + L"\n";
|
||||||
|
|
||||||
|
message += L" Thread: " + Threading::pxGetCurrentThreadName() + L"\n";
|
||||||
|
|
||||||
|
if( condition != NULL )
|
||||||
|
message += L" Condition: " + wxString(condition) + L"\n";
|
||||||
|
|
||||||
|
if( msg != NULL )
|
||||||
|
message += L" Message: " + wxString(msg) + L"\n";
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool pxAssertImpl_LogIt( const DiagnosticOrigin& origin, const wxChar *msg )
|
||||||
|
{
|
||||||
|
wxLogError( origin.ToString( msg ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVASSERT_INLINE void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg )
|
||||||
|
{
|
||||||
|
RecursionGuard guard( s_assert_guard );
|
||||||
|
if( guard.IsReentrant() ) { return wxTrap(); }
|
||||||
|
|
||||||
|
// wxWidgets doesn't come with debug builds on some Linux distros, and other distros make
|
||||||
|
// it difficult to use the debug build (compilation failures). To handle these I've had to
|
||||||
|
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
|
||||||
|
// PCSX2 itself is compiled in debug mode (assertions enabled).
|
||||||
|
|
||||||
|
bool trapit;
|
||||||
|
|
||||||
|
if( pxDoAssert == NULL )
|
||||||
{
|
{
|
||||||
// Note: Format uses MSVC's syntax for output window hotlinking.
|
// Note: Format uses MSVC's syntax for output window hotlinking.
|
||||||
wxLogError( wxsFormat( L"%s(%d): Assertion failed in %s: %s\n",
|
trapit = pxAssertImpl_LogIt( origin, msg );
|
||||||
file, line, fromUTF8(func).c_str(), msg )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef __WXDEBUG__
|
trapit = pxDoAssert( origin, msg );
|
||||||
wxTheApp->OnAssertFailure( file, line, fromUTF8(func), cond, msg );
|
|
||||||
#elif wxUSE_GUI
|
|
||||||
// FIXME: this should create a popup dialog for devel builds.
|
|
||||||
wxLogError( msg );
|
|
||||||
#else
|
|
||||||
wxLogError( msg );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
if( trapit ) { wxTrap(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline void pxOnAssert( const wxChar* file, int line, const char* func, const wxChar* cond, const char* msg)
|
__forceinline void pxOnAssert( const DiagnosticOrigin& origin, const char* msg)
|
||||||
{
|
{
|
||||||
pxOnAssert( file, line, func, cond, fromUTF8(msg) );
|
pxOnAssert( origin, fromUTF8(msg) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,61 @@ const wxTimeSpan Threading::def_yieldgui_interval( 0, 0, 0, 100 );
|
||||||
// three second interval for deadlock protection on waitgui.
|
// three second interval for deadlock protection on waitgui.
|
||||||
const wxTimeSpan Threading::def_deadlock_timeout( 0, 0, 3, 0 );
|
const wxTimeSpan Threading::def_deadlock_timeout( 0, 0, 3, 0 );
|
||||||
|
|
||||||
|
//static __threadlocal PersistentThread* tls_current_thread = NULL;
|
||||||
|
|
||||||
|
static pthread_key_t curthread_key = NULL;
|
||||||
|
static s32 total_key_count = 0;
|
||||||
|
static Mutex total_key_lock;
|
||||||
|
|
||||||
|
static void make_curthread_key()
|
||||||
|
{
|
||||||
|
ScopedLock lock( total_key_lock );
|
||||||
|
if( total_key_count++ != 0 ) return;
|
||||||
|
|
||||||
|
if( 0 != pthread_key_create(&curthread_key, NULL) )
|
||||||
|
{
|
||||||
|
Console.Error( "Thread key creation failed (probably out of memory >_<)" );
|
||||||
|
curthread_key = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unmake_curthread_key()
|
||||||
|
{
|
||||||
|
ScopedLock lock( total_key_lock );
|
||||||
|
if( --total_key_count > 0 ) return;
|
||||||
|
|
||||||
|
if( curthread_key != NULL )
|
||||||
|
pthread_key_delete( curthread_key );
|
||||||
|
|
||||||
|
curthread_key = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns a handle to the current persistent thread. If the current thread does not belong
|
||||||
|
// to the PersistentThread table, NULL is returned. Since the main/ui thread is not created
|
||||||
|
// through PersistentThread it will also return NULL. Callers can use wxThread::IsMain() to
|
||||||
|
// test if the NULL thread is the main thread.
|
||||||
|
PersistentThread* Threading::pxGetCurrentThread()
|
||||||
|
{
|
||||||
|
return (curthread_key==NULL) ? NULL : (PersistentThread*)pthread_getspecific( curthread_key );
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the name of the current thread, or "Unknown" if the thread is neither a PersistentThread
|
||||||
|
// nor the Main/UI thread.
|
||||||
|
wxString Threading::pxGetCurrentThreadName()
|
||||||
|
{
|
||||||
|
if( PersistentThread* thr = pxGetCurrentThread() )
|
||||||
|
{
|
||||||
|
return thr->GetName();
|
||||||
|
}
|
||||||
|
else if( wxThread::IsMain() )
|
||||||
|
{
|
||||||
|
return L"Main/UI";
|
||||||
|
}
|
||||||
|
|
||||||
|
return L"Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
// (intended for internal use only)
|
// (intended for internal use only)
|
||||||
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
||||||
// handled via normal yielding methods.
|
// handled via normal yielding methods.
|
||||||
|
@ -81,7 +136,7 @@ Threading::PersistentThread::PersistentThread()
|
||||||
// This destructor performs basic "last chance" cleanup, which is a blocking join
|
// This destructor performs basic "last chance" cleanup, which is a blocking join
|
||||||
// against the thread. Extending classes should almost always implement their own
|
// against the thread. Extending classes should almost always implement their own
|
||||||
// thread closure process, since any PersistentThread will, by design, not terminate
|
// thread closure process, since any PersistentThread will, by design, not terminate
|
||||||
// unless it has been properly canceled.
|
// unless it has been properly canceled (resulting in deadlock).
|
||||||
//
|
//
|
||||||
// Thread safety: This class must not be deleted from its own thread. That would be
|
// Thread safety: 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.
|
// like marrying your sister, and then cheating on her with your daughter.
|
||||||
|
@ -116,14 +171,24 @@ Threading::PersistentThread::~PersistentThread() throw()
|
||||||
DESTRUCTOR_CATCHALL
|
DESTRUCTOR_CATCHALL
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::PersistentThread::AffinityAssert_AllowFromSelf() const
|
bool Threading::PersistentThread::AffinityAssert_AllowFromSelf( const DiagnosticOrigin& origin ) const
|
||||||
{
|
{
|
||||||
return pxAssertMsg( IsSelf(), wxsFormat( L"Thread affinity violation: Call allowed from '%s' thread only.", m_name.c_str() ) );
|
if( IsSelf() ) return true;
|
||||||
|
|
||||||
|
if( IsDevBuild )
|
||||||
|
pxOnAssert( origin, wxsFormat( L"Thread affinity violation: Call allowed from '%s' thread only.", m_name.c_str() ) );
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::PersistentThread::AffinityAssert_DisallowFromSelf() const
|
bool Threading::PersistentThread::AffinityAssert_DisallowFromSelf( const DiagnosticOrigin& origin ) const
|
||||||
{
|
{
|
||||||
return pxAssertMsg( !IsSelf(), wxsFormat( L"Thread affinity violation: Call is *not* allowed from '%s' thread.", m_name.c_str() ) );
|
if( !IsSelf() ) return true;
|
||||||
|
|
||||||
|
if( IsDevBuild )
|
||||||
|
pxOnAssert( origin, wxsFormat( L"Thread affinity violation: Call is *not* allowed from '%s' thread.", m_name.c_str() ) );
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::PersistentThread::FrankenMutex( Mutex& mutex )
|
void Threading::PersistentThread::FrankenMutex( Mutex& mutex )
|
||||||
|
@ -157,7 +222,29 @@ void Threading::PersistentThread::Start()
|
||||||
m_except = NULL;
|
m_except = NULL;
|
||||||
|
|
||||||
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
|
||||||
throw Exception::ThreadCreationError();
|
throw Exception::ThreadCreationError( this );
|
||||||
|
|
||||||
|
if( !m_sem_startup.WaitWithoutYield( wxTimeSpan( 0, 0, 3, 0 ) ) )
|
||||||
|
{
|
||||||
|
RethrowException();
|
||||||
|
|
||||||
|
// And if the thread threw nothing of its own:
|
||||||
|
throw Exception::ThreadCreationError( this, "(%s thread) Start error: created thread never posted startup semaphore." );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event Rationale (above): Performing this semaphore wait on the created thread is "slow" in the
|
||||||
|
// sense that it stalls the calling thread completely until the new thread is created
|
||||||
|
// (which may not always be desirable). But too bad. In order to safely use 'running' locks
|
||||||
|
// and detachment management, this *has* to be done. By rule, starting new threads shouldn't
|
||||||
|
// be done very often anyway, hence the concept of Threadpooling for rapidly rotating tasks.
|
||||||
|
// (and indeed, this semaphore wait might, in fact, be very swift compared to other kernel
|
||||||
|
// overhead in starting threads).
|
||||||
|
|
||||||
|
// (this could also be done using operating system specific calls, since any threaded OS has
|
||||||
|
// functions that allow us to see if a thread is running or not, and to block against it even if
|
||||||
|
// it's been detached -- removing the need for m_lock_InThread and the semaphore wait above. But
|
||||||
|
// pthreads kinda lacks that stuff, since pthread_join() has no timeout option making it im-
|
||||||
|
// possible to safely block against a running thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns: TRUE if the detachment was performed, or FALSE if the thread was
|
// Returns: TRUE if the detachment was performed, or FALSE if the thread was
|
||||||
|
@ -165,13 +252,28 @@ void Threading::PersistentThread::Start()
|
||||||
// This function should not be called from the owner thread.
|
// This function should not be called from the owner thread.
|
||||||
bool Threading::PersistentThread::Detach()
|
bool Threading::PersistentThread::Detach()
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf();
|
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||||
|
|
||||||
if( _InterlockedExchange( &m_detached, true ) ) return false;
|
if( _InterlockedExchange( &m_detached, true ) ) return false;
|
||||||
pthread_detach( m_thread );
|
pthread_detach( m_thread );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Threading::PersistentThread::_basecancel()
|
||||||
|
{
|
||||||
|
// Prevent simultaneous startup and cancel:
|
||||||
|
if( !m_running ) return false;
|
||||||
|
|
||||||
|
if( m_detached )
|
||||||
|
{
|
||||||
|
Console.Warning( "(Thread Warning) Ignoring attempted cancellation of detached thread." );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_cancel( m_thread );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Remarks:
|
// Remarks:
|
||||||
// Provision of non-blocking Cancel() is probably academic, since destroying a PersistentThread
|
// 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()
|
// object performs a blocking Cancel regardless of if you explicitly do a non-blocking Cancel()
|
||||||
|
@ -183,33 +285,40 @@ bool Threading::PersistentThread::Detach()
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// isBlocking - indicates if the Cancel action should block for thread completion or not.
|
// isBlocking - indicates if the Cancel action should block for thread completion or not.
|
||||||
//
|
//
|
||||||
|
// Exceptions raised by the blocking thread will be re-thrown into the main thread. If isBlocking
|
||||||
|
// is false then no exceptions will occur.
|
||||||
|
//
|
||||||
void Threading::PersistentThread::Cancel( bool isBlocking )
|
void Threading::PersistentThread::Cancel( bool isBlocking )
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf();
|
AffinityAssert_DisallowFromSelf( pxDiagSpot );
|
||||||
|
|
||||||
{
|
// Prevent simultaneous startup and cancel, necessary to avoid
|
||||||
// Prevent simultaneous startup and cancel:
|
ScopedLock startlock( m_lock_start );
|
||||||
ScopedLock startlock( m_lock_start );
|
|
||||||
if( !m_running ) return;
|
|
||||||
|
|
||||||
if( m_detached )
|
if( !_basecancel() ) return;
|
||||||
{
|
|
||||||
Console.Warning( "(Thread Warning) Ignoring attempted cancellation of detached thread." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_cancel( m_thread );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if( isBlocking )
|
if( isBlocking )
|
||||||
{
|
{
|
||||||
// FIXME: Add deadlock detection and handling here... ?
|
WaitOnSelf( m_lock_InThread );
|
||||||
m_lock_InThread.Wait();
|
|
||||||
Detach();
|
Detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Threading::PersistentThread::Cancel( const wxTimeSpan& timespan )
|
||||||
|
{
|
||||||
|
AffinityAssert_DisallowFromSelf( pxDiagSpot );
|
||||||
|
|
||||||
|
// Prevent simultaneous startup and cancel:
|
||||||
|
ScopedLock startlock( m_lock_start );
|
||||||
|
|
||||||
|
if( !_basecancel() ) return true;
|
||||||
|
|
||||||
|
if( !WaitOnSelf( m_lock_InThread, timespan ) ) return false;
|
||||||
|
Detach();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Blocks execution of the calling thread until this thread completes its task. The
|
// Blocks execution of the calling thread until this thread completes its task. The
|
||||||
// caller should make sure to signal the thread to exit, or else blocking may deadlock the
|
// caller should make sure to signal the thread to exit, or else blocking may deadlock the
|
||||||
// calling thread. Classes which extend PersistentThread should override this method
|
// calling thread. Classes which extend PersistentThread should override this method
|
||||||
|
@ -218,10 +327,12 @@ void Threading::PersistentThread::Cancel( bool isBlocking )
|
||||||
// Returns the return code of the thread.
|
// Returns the return code of the thread.
|
||||||
// This method is roughly the equivalent of pthread_join().
|
// This method is roughly the equivalent of pthread_join().
|
||||||
//
|
//
|
||||||
|
// Exceptions raised by the blocking thread will be re-thrown into the main thread.
|
||||||
|
//
|
||||||
void Threading::PersistentThread::Block()
|
void Threading::PersistentThread::Block()
|
||||||
{
|
{
|
||||||
AffinityAssert_DisallowFromSelf();
|
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||||
m_lock_InThread.Wait();
|
WaitOnSelf( m_lock_InThread );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Threading::PersistentThread::IsSelf() const
|
bool Threading::PersistentThread::IsSelf() const
|
||||||
|
@ -277,7 +388,7 @@ void Threading::PersistentThread::_selfRunningTest( const wxChar* name ) const
|
||||||
//
|
//
|
||||||
void Threading::PersistentThread::WaitOnSelf( Semaphore& sem ) const
|
void Threading::PersistentThread::WaitOnSelf( Semaphore& sem ) const
|
||||||
{
|
{
|
||||||
if( !AffinityAssert_DisallowFromSelf() ) return;
|
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return;
|
||||||
|
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
|
@ -301,7 +412,7 @@ void Threading::PersistentThread::WaitOnSelf( Semaphore& sem ) const
|
||||||
//
|
//
|
||||||
void Threading::PersistentThread::WaitOnSelf( Mutex& mutex ) const
|
void Threading::PersistentThread::WaitOnSelf( Mutex& mutex ) const
|
||||||
{
|
{
|
||||||
if( !AffinityAssert_DisallowFromSelf() ) return;
|
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return;
|
||||||
|
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
|
@ -314,7 +425,7 @@ static const wxTimeSpan SelfWaitInterval( 0,0,0,333 );
|
||||||
|
|
||||||
bool Threading::PersistentThread::WaitOnSelf( Semaphore& sem, const wxTimeSpan& timeout ) const
|
bool Threading::PersistentThread::WaitOnSelf( Semaphore& sem, const wxTimeSpan& timeout ) const
|
||||||
{
|
{
|
||||||
if( !AffinityAssert_DisallowFromSelf() ) return true;
|
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return true;
|
||||||
|
|
||||||
wxTimeSpan runningout( timeout );
|
wxTimeSpan runningout( timeout );
|
||||||
|
|
||||||
|
@ -330,7 +441,7 @@ bool Threading::PersistentThread::WaitOnSelf( Semaphore& sem, const wxTimeSpan&
|
||||||
|
|
||||||
bool Threading::PersistentThread::WaitOnSelf( Mutex& mutex, const wxTimeSpan& timeout ) const
|
bool Threading::PersistentThread::WaitOnSelf( Mutex& mutex, const wxTimeSpan& timeout ) const
|
||||||
{
|
{
|
||||||
if( !AffinityAssert_DisallowFromSelf() ) return true;
|
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return true;
|
||||||
|
|
||||||
wxTimeSpan runningout( timeout );
|
wxTimeSpan runningout( timeout );
|
||||||
|
|
||||||
|
@ -350,7 +461,7 @@ bool Threading::PersistentThread::WaitOnSelf( Mutex& mutex, const wxTimeSpan& ti
|
||||||
// and cleanup, or use the DoThreadCleanup() override to perform resource cleanup).
|
// and cleanup, or use the DoThreadCleanup() override to perform resource cleanup).
|
||||||
void Threading::PersistentThread::TestCancel() const
|
void Threading::PersistentThread::TestCancel() const
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFromSelf();
|
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||||
pthread_testcancel();
|
pthread_testcancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,24 +504,16 @@ void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*
|
||||||
}
|
}
|
||||||
#ifndef PCSX2_DEVBUILD
|
#ifndef PCSX2_DEVBUILD
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Allow logic errors to propagate out of the thread in release builds, so that they might be
|
// Bleh... don't bother with std::exception. runtime_error should catch anything
|
||||||
// handled in non-fatal ways. On Devbuilds let them loose, so that they produce debug stack
|
// useful coming out of the core STL libraries anyway, and these are best handled by
|
||||||
// traces and such.
|
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
||||||
catch( std::logic_error& ex )
|
/*catch( std::logic_error& ex )
|
||||||
{
|
{
|
||||||
throw Exception::LogicError( wxsFormat( L"(thread: %s) STL Logic Error: %s\n\t%s",
|
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL Logic Error: %s\n\t%s",
|
||||||
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch( Exception::LogicError& ex )
|
catch( std::exception& ex )
|
||||||
{
|
|
||||||
m_except = ex.Clone();
|
|
||||||
m_except->DiagMsg() = wxsFormat( L"(thread:%s) ", GetName().c_str() ) + m_except->DiagMsg();
|
|
||||||
}
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Bleh... don't bother with std::exception. std::logic_error and runtime_error should catch
|
|
||||||
// anything coming out of the core STL libraries anyway.
|
|
||||||
/*catch( std::exception& ex )
|
|
||||||
{
|
{
|
||||||
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL exception: %s\n\t%s",
|
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL exception: %s\n\t%s",
|
||||||
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
GetName().c_str(), fromUTF8( ex.what() ).c_str() )
|
||||||
|
@ -431,7 +534,7 @@ void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*
|
||||||
// OnCleanupInThread() to extend cleanup functionality.
|
// OnCleanupInThread() to extend cleanup functionality.
|
||||||
void Threading::PersistentThread::_ThreadCleanup()
|
void Threading::PersistentThread::_ThreadCleanup()
|
||||||
{
|
{
|
||||||
AffinityAssert_AllowFromSelf();
|
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||||
_try_virtual_invoke( &PersistentThread::OnCleanupInThread );
|
_try_virtual_invoke( &PersistentThread::OnCleanupInThread );
|
||||||
m_lock_InThread.Release();
|
m_lock_InThread.Release();
|
||||||
}
|
}
|
||||||
|
@ -442,42 +545,59 @@ wxString Threading::PersistentThread::GetName() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// This override is called by PeristentThread when the thread is first created, prior to
|
// This override is called by PeristentThread when the thread is first created, prior to
|
||||||
// calling ExecuteTaskInThread. This is useful primarily for "base" classes that extend
|
// calling ExecuteTaskInThread, and after the initial InThread lock has been claimed.
|
||||||
// from PersistentThread, giving them the ability to bind startup code to all threads that
|
// This code is also executed within a "safe" environment, where the creating thread is
|
||||||
// derive from them. (the alternative would have been to make ExecuteTaskInThread a
|
// blocked against m_sem_event. Make sure to do any necessary variable setup here, without
|
||||||
// private member, and provide a new Task executor by a different name).
|
// worry that the calling thread might attempt to test the status of those variables
|
||||||
|
// before initialization has completed.
|
||||||
|
//
|
||||||
void Threading::PersistentThread::OnStartInThread()
|
void Threading::PersistentThread::OnStartInThread()
|
||||||
{
|
{
|
||||||
m_running = true;
|
|
||||||
m_detached = false;
|
m_detached = false;
|
||||||
|
m_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Threading::PersistentThread::_internal_execute()
|
void Threading::PersistentThread::_internal_execute()
|
||||||
{
|
{
|
||||||
m_lock_InThread.Acquire();
|
m_lock_InThread.Acquire();
|
||||||
OnStartInThread();
|
|
||||||
|
|
||||||
_DoSetThreadName( m_name );
|
_DoSetThreadName( m_name );
|
||||||
|
make_curthread_key();
|
||||||
|
if( curthread_key != NULL )
|
||||||
|
pthread_setspecific( curthread_key, this );
|
||||||
|
|
||||||
|
OnStartInThread();
|
||||||
|
m_sem_startup.Post();
|
||||||
|
|
||||||
_try_virtual_invoke( &PersistentThread::ExecuteTaskInThread );
|
_try_virtual_invoke( &PersistentThread::ExecuteTaskInThread );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called by Start, prior to actual starting of the thread, and after any previous
|
||||||
|
// running thread has been canceled or detached.
|
||||||
void Threading::PersistentThread::OnStart()
|
void Threading::PersistentThread::OnStart()
|
||||||
{
|
{
|
||||||
FrankenMutex( m_lock_InThread );
|
FrankenMutex( m_lock_InThread );
|
||||||
m_sem_event.Reset();
|
m_sem_event.Reset();
|
||||||
|
m_sem_startup.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extending classes that override this method shoul always call it last from their
|
||||||
|
// personal implementations.
|
||||||
void Threading::PersistentThread::OnCleanupInThread()
|
void Threading::PersistentThread::OnCleanupInThread()
|
||||||
{
|
{
|
||||||
m_running = false;
|
m_running = false;
|
||||||
|
|
||||||
|
if( curthread_key != NULL )
|
||||||
|
pthread_setspecific( curthread_key, NULL );
|
||||||
|
|
||||||
|
unmake_curthread_key();
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
// passed into pthread_create, and is used to dispatch the thread's object oriented
|
||||||
// callback function
|
// callback function
|
||||||
void* Threading::PersistentThread::_internal_callback( void* itsme )
|
void* Threading::PersistentThread::_internal_callback( void* itsme )
|
||||||
{
|
{
|
||||||
pxAssert( itsme != NULL );
|
if( !pxAssertDev( itsme != NULL, wxNullChar ) ) return NULL;
|
||||||
PersistentThread& owner = *((PersistentThread*)itsme);
|
PersistentThread& owner = *((PersistentThread*)itsme);
|
||||||
|
|
||||||
pthread_cleanup_push( _pt_callback_cleanup, itsme );
|
pthread_cleanup_push( _pt_callback_cleanup, itsme );
|
||||||
|
@ -493,8 +613,6 @@ void Threading::PersistentThread::_DoSetThreadName( const wxString& name )
|
||||||
|
|
||||||
void Threading::PersistentThread::_DoSetThreadName( const char* name )
|
void Threading::PersistentThread::_DoSetThreadName( const char* name )
|
||||||
{
|
{
|
||||||
if( !AffinityAssert_AllowFromSelf() ) return;
|
|
||||||
|
|
||||||
// This feature needs Windows headers and MSVC's SEH support:
|
// This feature needs Windows headers and MSVC's SEH support:
|
||||||
|
|
||||||
#if defined(_WINDOWS_) && defined (_MSC_VER)
|
#if defined(_WINDOWS_) && defined (_MSC_VER)
|
||||||
|
|
|
@ -81,3 +81,8 @@ void operator+=( wxSizer& target, pxCheckBox& src )
|
||||||
{
|
{
|
||||||
target.Add( &src, wxSF.Expand() );
|
target.Add( &src, wxSF.Expand() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator+=( wxSizer* target, pxCheckBox& src )
|
||||||
|
{
|
||||||
|
target->Add( &src, wxSF.Expand() );
|
||||||
|
}
|
||||||
|
|
|
@ -149,13 +149,13 @@ void pxRadioPanel::_RealizeDefaultOption()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxRadioPanel& pxRadioPanel::SetDefault( int idx )
|
pxRadioPanel& pxRadioPanel::SetDefaultItem( int idx )
|
||||||
{
|
{
|
||||||
if( idx == m_DefaultIdx ) return *this;
|
if( idx == m_DefaultIdx ) return *this;
|
||||||
|
|
||||||
if( m_IsRealized && m_DefaultIdx != -1 )
|
if( m_IsRealized && m_DefaultIdx != -1 )
|
||||||
{
|
{
|
||||||
wxFont def( GetFont() );
|
wxFont def(GetFont());
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetFont( def );
|
m_objects[m_DefaultIdx].LabelObj->SetFont( def );
|
||||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour( GetForegroundColour() );
|
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour( GetForegroundColour() );
|
||||||
}
|
}
|
||||||
|
@ -166,6 +166,20 @@ pxRadioPanel& pxRadioPanel::SetDefault( int idx )
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pxRadioPanel& pxRadioPanel::EnableItem( int idx, bool enable )
|
||||||
|
{
|
||||||
|
pxAssertDev( m_IsRealized, "RadioPanel must be realized first, prior to enabling or disabling individual items." );
|
||||||
|
|
||||||
|
if( m_objects[idx].LabelObj )
|
||||||
|
m_objects[idx].LabelObj->Enable( enable );
|
||||||
|
|
||||||
|
if( m_objects[idx].SubTextObj )
|
||||||
|
m_objects[idx].SubTextObj->Enable( enable );
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int pxRadioPanel::GetSelection() const
|
int pxRadioPanel::GetSelection() const
|
||||||
{
|
{
|
||||||
if( !VerifyRealizedState() ) return 0;
|
if( !VerifyRealizedState() ) return 0;
|
||||||
|
|
|
@ -131,3 +131,8 @@ void operator+=( wxSizer& target, pxStaticText& src )
|
||||||
{
|
{
|
||||||
src.AddTo( target );
|
src.AddTo( target );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator+=( wxSizer* target, pxStaticText& src )
|
||||||
|
{
|
||||||
|
src.AddTo( target );
|
||||||
|
}
|
||||||
|
|
|
@ -99,7 +99,12 @@ wxSizerFlags pxStretchType::Apply( wxSizerFlags flags ) const
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSizerFlags operator , ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 )
|
wxSizerFlags pxProportion::Apply( wxSizerFlags flags ) const
|
||||||
|
{
|
||||||
|
return flags.Proportion( intval );
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSizerFlags operator& ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 )
|
||||||
{
|
{
|
||||||
//return align.Apply( _flgs );
|
//return align.Apply( _flgs );
|
||||||
wxSizerFlags retval;
|
wxSizerFlags retval;
|
||||||
|
@ -118,11 +123,8 @@ wxSizerFlags operator , ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*wxSizerFlags operator | ( const wxSizerFlags& _flgs, pxStretchType stretch )
|
// ----------------------------------------------------------------------------
|
||||||
{
|
// Reference/Handle versions!
|
||||||
return stretch.Apply( _flgs );
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
void operator+=( wxSizer& target, wxWindow* src )
|
void operator+=( wxSizer& target, wxWindow* src )
|
||||||
{
|
{
|
||||||
|
@ -148,6 +150,23 @@ void operator+=( wxSizer& target, int spacer )
|
||||||
{
|
{
|
||||||
target.AddSpacer( spacer );
|
target.AddSpacer( spacer );
|
||||||
}
|
}
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Pointer versions! (note that C++ requires one of the two operator params be a
|
||||||
|
// "poper" object type (non-pointer), so that's why there's only a couple of these.
|
||||||
|
|
||||||
|
void operator+=( wxSizer* target, wxWindow& src )
|
||||||
|
{
|
||||||
|
if( !pxAssert( target != NULL ) ) return;
|
||||||
|
target->Add( &src );
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator+=( wxSizer* target, wxSizer& src )
|
||||||
|
{
|
||||||
|
if( !pxAssert( target != NULL ) ) return;
|
||||||
|
target->Add( &src );
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
void operator+=( wxWindow& target, int spacer )
|
void operator+=( wxWindow& target, int spacer )
|
||||||
{
|
{
|
||||||
|
@ -431,3 +450,14 @@ void pxSetToolTip( wxWindow& wind, const wxString& src )
|
||||||
{
|
{
|
||||||
pxSetToolTip( &wind, src );
|
pxSetToolTip( &wind, src );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxFont pxGetFixedFont( int ptsize, int weight )
|
||||||
|
{
|
||||||
|
return wxFont(
|
||||||
|
ptsize, wxMODERN, wxNORMAL, weight, false,
|
||||||
|
#ifdef __WXMSW__
|
||||||
|
L"Lucida Console" // better than courier new (win32 only)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -28,13 +28,9 @@ using namespace pxSizerFlags;
|
||||||
// wxDialogWithHelpers Class Implementations
|
// wxDialogWithHelpers Class Implementations
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
|
|
||||||
HashTools::HashMap< wxWindowID, int > m_DialogIdents( 0, wxID_ANY );
|
bool pxDialogExists( const wxString& name )
|
||||||
|
|
||||||
bool pxDialogExists( wxWindowID id )
|
|
||||||
{
|
{
|
||||||
int dest = 0;
|
return wxFindWindowByName( name ) != NULL;
|
||||||
m_DialogIdents.TryGetValue( id, dest );
|
|
||||||
return (dest > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -44,20 +40,41 @@ IMPLEMENT_DYNAMIC_CLASS(wxDialogWithHelpers, wxDialog)
|
||||||
|
|
||||||
wxDialogWithHelpers::wxDialogWithHelpers()
|
wxDialogWithHelpers::wxDialogWithHelpers()
|
||||||
{
|
{
|
||||||
m_idealWidth = wxDefaultCoord;
|
|
||||||
m_hasContextHelp = false;
|
m_hasContextHelp = false;
|
||||||
m_extraButtonSizer = NULL;
|
m_extraButtonSizer = NULL;
|
||||||
|
|
||||||
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, int id, const wxString& title, bool hasContextHelp, const wxPoint& pos, const wxSize& size )
|
wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, const wxString& title, bool hasContextHelp, bool resizable )
|
||||||
: wxDialog( parent, id, title, pos, size , wxDEFAULT_DIALOG_STYLE) //, (wxCAPTION | wxMAXIMIZE | wxCLOSE_BOX | wxRESIZE_BORDER) ), // flags for resizable dialogs, currently unused.
|
: wxDialog( parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize,
|
||||||
|
wxDEFAULT_DIALOG_STYLE | (resizable ? wxRESIZE_BORDER : 0)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
++m_DialogIdents[GetId()];
|
m_hasContextHelp = hasContextHelp;
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDialogWithHelpers::wxDialogWithHelpers(wxWindow* parent, const wxString& title, wxOrientation orient)
|
||||||
|
: wxDialog( parent, wxID_ANY, title )
|
||||||
|
{
|
||||||
|
m_hasContextHelp = false;
|
||||||
|
SetSizer( new wxBoxSizer( orient ) );
|
||||||
|
Init();
|
||||||
|
|
||||||
|
m_idealWidth = 500;
|
||||||
|
*this += StdPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDialogWithHelpers::~wxDialogWithHelpers() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxDialogWithHelpers::Init()
|
||||||
|
{
|
||||||
m_idealWidth = wxDefaultCoord;
|
m_idealWidth = wxDefaultCoord;
|
||||||
m_extraButtonSizer = NULL;
|
m_extraButtonSizer = NULL;
|
||||||
|
|
||||||
m_hasContextHelp = hasContextHelp;
|
|
||||||
if( m_hasContextHelp )
|
if( m_hasContextHelp )
|
||||||
delete wxHelpProvider::Set( new wxSimpleHelpProvider() );
|
delete wxHelpProvider::Set( new wxSimpleHelpProvider() );
|
||||||
|
|
||||||
|
@ -65,14 +82,54 @@ wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, int id, const wxStr
|
||||||
// indicate that it should, so I presume the problem is in wxWidgets and that (hopefully!)
|
// indicate that it should, so I presume the problem is in wxWidgets and that (hopefully!)
|
||||||
// an updated version will fix it later. I tried to fix it using a manual Connect but it
|
// an updated version will fix it later. I tried to fix it using a manual Connect but it
|
||||||
// didn't do any good. (problem could also be my Co-Linux / x-window manager)
|
// didn't do any good. (problem could also be my Co-Linux / x-window manager)
|
||||||
|
|
||||||
//Connect( wxEVT_ACTIVATE, wxActivateEventHandler(wxDialogWithHelpers::OnActivate) );
|
//Connect( wxEVT_ACTIVATE, wxActivateEventHandler(wxDialogWithHelpers::OnActivate) );
|
||||||
|
|
||||||
|
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (wxDialogWithHelpers::OnOkCancel) );
|
||||||
|
Connect( wxID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (wxDialogWithHelpers::OnOkCancel) );
|
||||||
|
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (wxDialogWithHelpers::OnCloseWindow) );
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDialogWithHelpers::~wxDialogWithHelpers() throw()
|
void wxDialogWithHelpers::SmartCenterFit()
|
||||||
{
|
{
|
||||||
--m_DialogIdents[GetId()];
|
Fit();
|
||||||
pxAssert( m_DialogIdents[GetId()] >= 0 );
|
|
||||||
|
// Smart positioning logic! If our parent window is larger than our window by some
|
||||||
|
// good amount, then we center on that. If not, center relative to the screen. This
|
||||||
|
// avoids the popup automatically eclipsing the parent window (which happens in PCSX2
|
||||||
|
// a lot since the main window is small).
|
||||||
|
|
||||||
|
bool centerfail = true;
|
||||||
|
if( wxWindow* parent = GetParent() )
|
||||||
|
{
|
||||||
|
const wxSize parentSize( parent->GetSize() );
|
||||||
|
|
||||||
|
if( (parentSize.x > ((int)GetSize().x * 1.75)) && (parentSize.y > ((int)GetSize().y * 1.75)) )
|
||||||
|
{
|
||||||
|
CenterOnParent();
|
||||||
|
centerfail = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( centerfail ) CenterOnScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides wxDialog behavior to include automatic Fit() and CenterOnParent/Screen. The centering
|
||||||
|
// is based on a heuristic the centers against the parent window if the parent window is at least
|
||||||
|
// 75% larger than the fitted dialog.
|
||||||
|
int wxDialogWithHelpers::ShowModal()
|
||||||
|
{
|
||||||
|
SmartCenterFit();
|
||||||
|
return wxDialog::ShowModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides wxDialog behavior to include automatic Fit() and CenterOnParent/Screen. The centering
|
||||||
|
// is based on a heuristic the centers against the parent window if the parent window is at least
|
||||||
|
// 75% larger than the fitted dialog.
|
||||||
|
bool wxDialogWithHelpers::Show( bool show )
|
||||||
|
{
|
||||||
|
if( show ) SmartCenterFit();
|
||||||
|
return wxDialog::Show( show );
|
||||||
}
|
}
|
||||||
|
|
||||||
pxStaticText* wxDialogWithHelpers::Text( const wxString& label )
|
pxStaticText* wxDialogWithHelpers::Text( const wxString& label )
|
||||||
|
@ -85,6 +142,19 @@ pxStaticHeading* wxDialogWithHelpers::Heading( const wxString& label )
|
||||||
return new pxStaticHeading( this, label );
|
return new pxStaticHeading( this, label );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxDialogWithHelpers::OnCloseWindow( wxCloseEvent& evt )
|
||||||
|
{
|
||||||
|
if( !IsModal() ) Destroy();
|
||||||
|
evt.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxDialogWithHelpers::OnOkCancel( wxCommandEvent& evt )
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
evt.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void wxDialogWithHelpers::OnActivate(wxActivateEvent& evt)
|
void wxDialogWithHelpers::OnActivate(wxActivateEvent& evt)
|
||||||
{
|
{
|
||||||
//evt.Skip();
|
//evt.Skip();
|
||||||
|
@ -119,7 +189,7 @@ void wxDialogWithHelpers::AddOkCancel( wxSizer &sizer, bool hasApply )
|
||||||
flex.AddGrowableCol( 1, 15 );
|
flex.AddGrowableCol( 1, 15 );
|
||||||
|
|
||||||
flex += m_extraButtonSizer | pxAlignLeft;
|
flex += m_extraButtonSizer | pxAlignLeft;
|
||||||
flex += s_buttons | pxExpand, pxCenter;
|
flex += s_buttons | (pxExpand & pxCenter);
|
||||||
|
|
||||||
sizer += flex | StdExpand();
|
sizer += flex | StdExpand();
|
||||||
|
|
||||||
|
|
|
@ -592,7 +592,7 @@ $memcpy_final:
|
||||||
// (zerofrog)
|
// (zerofrog)
|
||||||
u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize)
|
u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize)
|
||||||
{
|
{
|
||||||
assert( (cmpsize&7) == 0 );
|
pxAssert( (cmpsize&7) == 0 );
|
||||||
|
|
||||||
__asm {
|
__asm {
|
||||||
push esi
|
push esi
|
||||||
|
@ -766,7 +766,7 @@ End:
|
||||||
// returns the xor of all elements, cmpsize has to be mult of 8
|
// returns the xor of all elements, cmpsize has to be mult of 8
|
||||||
void memxor_mmx(void* dst, const void* src1, int cmpsize)
|
void memxor_mmx(void* dst, const void* src1, int cmpsize)
|
||||||
{
|
{
|
||||||
assert( (cmpsize&7) == 0 );
|
pxAssert( (cmpsize&7) == 0 );
|
||||||
|
|
||||||
__asm {
|
__asm {
|
||||||
mov ecx, cmpsize
|
mov ecx, cmpsize
|
||||||
|
|
|
@ -745,7 +745,7 @@ __forceinline void cdvdReadInterrupt()
|
||||||
// An arbitrary delay of some number of cycles probably makes more sense here,
|
// An arbitrary delay of some number of cycles probably makes more sense here,
|
||||||
// but for now it's based on the cdvd.ReadTime value. -- air
|
// but for now it's based on the cdvd.ReadTime value. -- air
|
||||||
|
|
||||||
assert((int)cdvd.ReadTime > 0 );
|
pxAssume((int)cdvd.ReadTime > 0 );
|
||||||
CDVDREAD_INT(cdvd.ReadTime/4);
|
CDVDREAD_INT(cdvd.ReadTime/4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,7 +340,7 @@ static __forceinline void frameLimit()
|
||||||
static __forceinline void VSyncStart(u32 sCycle)
|
static __forceinline void VSyncStart(u32 sCycle)
|
||||||
{
|
{
|
||||||
Cpu->CheckExecutionState();
|
Cpu->CheckExecutionState();
|
||||||
SysCoreThread::Get().VsyncInThread();
|
GetCoreThread().VsyncInThread();
|
||||||
|
|
||||||
EECNT_LOG( "///////// EE COUNTER VSYNC START (frame: %6d) \\\\\\\\\\\\\\\\\\\\ ", iFrame );
|
EECNT_LOG( "///////// EE COUNTER VSYNC START (frame: %6d) \\\\\\\\\\\\\\\\\\\\ ", iFrame );
|
||||||
|
|
||||||
|
|
|
@ -382,15 +382,16 @@ static void intExecute()
|
||||||
// Mem protection should be handled by the caller here so that it can be
|
// Mem protection should be handled by the caller here so that it can be
|
||||||
// done in a more optimized fashion.
|
// done in a more optimized fashion.
|
||||||
|
|
||||||
while( true )
|
try {
|
||||||
{
|
while( true )
|
||||||
execI();
|
execI();
|
||||||
}
|
} catch( Exception::ForceDispatcherReg& ) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intCheckExecutionState()
|
static void intCheckExecutionState()
|
||||||
{
|
{
|
||||||
SysCoreThread::Get().StateCheckInThread();
|
if( GetCoreThread().HasPendingStateChangeRequest() )
|
||||||
|
throw Exception::ForceDispatcherReg();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intStep()
|
static void intStep()
|
||||||
|
|
|
@ -680,7 +680,7 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] )
|
||||||
Console.WriteLn( L"Binding %s\t: %s ", tbl_PluginInfo[pid].GetShortname().c_str(), folders[pid].c_str() );
|
Console.WriteLn( L"Binding %s\t: %s ", tbl_PluginInfo[pid].GetShortname().c_str(), folders[pid].c_str() );
|
||||||
|
|
||||||
if( folders[pid].IsEmpty() )
|
if( folders[pid].IsEmpty() )
|
||||||
throw Exception::InvalidArgument( "Empty plugin filename." );
|
throw Exception::PluginInitError( pi->id, "Empty plugin filename." );
|
||||||
|
|
||||||
m_info[pid].Filename = folders[pid];
|
m_info[pid].Filename = folders[pid];
|
||||||
|
|
||||||
|
@ -985,6 +985,14 @@ void PluginManager::Close( PluginsEnum_t pid )
|
||||||
|
|
||||||
void PluginManager::Close( bool closegs )
|
void PluginManager::Close( bool closegs )
|
||||||
{
|
{
|
||||||
|
// 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..." );
|
DbgCon.WriteLn( Color_StrongBlue, "Closing plugins..." );
|
||||||
|
|
||||||
// Close plugins in reverse order of the initialization procedure.
|
// Close plugins in reverse order of the initialization procedure.
|
||||||
|
|
|
@ -39,7 +39,6 @@ R5900cpu *Cpu = NULL;
|
||||||
|
|
||||||
bool g_ExecBiosHack = false; // set if the BIOS has already been executed
|
bool g_ExecBiosHack = false; // set if the BIOS has already been executed
|
||||||
|
|
||||||
static bool cpuIsInitialized = false;
|
|
||||||
static const uint eeWaitCycles = 3072;
|
static const uint eeWaitCycles = 3072;
|
||||||
|
|
||||||
bool eeEventTestIsActive = false;
|
bool eeEventTestIsActive = false;
|
||||||
|
@ -52,10 +51,6 @@ void cpuReset()
|
||||||
if( GetMTGS().IsOpen() )
|
if( GetMTGS().IsOpen() )
|
||||||
GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||||
|
|
||||||
SysClearExecutionCache();
|
|
||||||
|
|
||||||
cpuIsInitialized = true;
|
|
||||||
|
|
||||||
memReset();
|
memReset();
|
||||||
psxMemReset();
|
psxMemReset();
|
||||||
vuMicroMemReset();
|
vuMicroMemReset();
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
* 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-
|
* 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.
|
* ation, either version 3 of te License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
* 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
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
@ -22,8 +22,11 @@
|
||||||
|
|
||||||
class _BaseStateThread;
|
class _BaseStateThread;
|
||||||
|
|
||||||
|
// Used to hold the current state backup (fullcopy of PS2 memory and plugin states).
|
||||||
static SafeArray<u8> state_buffer;
|
static SafeArray<u8> state_buffer;
|
||||||
|
|
||||||
|
_BaseStateThread* current_state_thread = NULL;
|
||||||
|
|
||||||
// Simple lock boolean for the state buffer being in use by a thread.
|
// Simple lock boolean for the state buffer being in use by a thread.
|
||||||
static NonblockingMutex state_buffer_lock;
|
static NonblockingMutex state_buffer_lock;
|
||||||
|
|
||||||
|
@ -56,9 +59,22 @@ class _BaseStateThread : public PersistentThread
|
||||||
protected:
|
protected:
|
||||||
EventListenerBinding<AppEventType> m_bind_OnExit;
|
EventListenerBinding<AppEventType> m_bind_OnExit;
|
||||||
|
|
||||||
|
bool m_isStarted;
|
||||||
|
|
||||||
|
// Holds the pause/suspend state of the emulator when the state load/stave chain of action is started,
|
||||||
|
// so that the proper state can be restoed automatically on completion.
|
||||||
|
bool m_resume_when_done;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~_BaseStateThread() throw()
|
virtual ~_BaseStateThread() throw()
|
||||||
{
|
{
|
||||||
|
if( !m_isStarted ) return;
|
||||||
|
|
||||||
|
// Assertion fails because C++ changes the 'this' pointer to the base class since
|
||||||
|
// derived classes have been deallocated at this point the destructor!
|
||||||
|
|
||||||
|
//pxAssumeDev( current_state_thread == this, wxCharNull );
|
||||||
|
current_state_thread = NULL;
|
||||||
state_buffer_lock.Release(); // just in case;
|
state_buffer_lock.Release(); // just in case;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,14 +83,18 @@ protected:
|
||||||
m_bind_OnExit( wxGetApp().Source_AppStatus(), EventListener<AppEventType>( this, StateThread_OnAppStatus ) )
|
m_bind_OnExit( wxGetApp().Source_AppStatus(), EventListener<AppEventType>( this, StateThread_OnAppStatus ) )
|
||||||
{
|
{
|
||||||
Callback_FreezeFinished = onFinished;
|
Callback_FreezeFinished = onFinished;
|
||||||
m_name = L"StateThread::" + fromUTF8(name);
|
m_name = L"StateThread::" + fromUTF8(name);
|
||||||
|
m_isStarted = false;
|
||||||
|
m_resume_when_done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnStart()
|
void OnStart()
|
||||||
{
|
{
|
||||||
if( !state_buffer_lock.TryAcquire() )
|
if( !state_buffer_lock.TryAcquire() )
|
||||||
throw Exception::CancelEvent( m_name + L"request ignored: state copy buffer is already locked!" );
|
throw Exception::CancelEvent( m_name + L"request ignored: state copy buffer is already locked!" );
|
||||||
|
|
||||||
|
current_state_thread = this;
|
||||||
|
m_isStarted = true;
|
||||||
_parent::OnStart();
|
_parent::OnStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +103,7 @@ protected:
|
||||||
wxCommandEvent evt( pxEVT_FreezeThreadFinished );
|
wxCommandEvent evt( pxEVT_FreezeThreadFinished );
|
||||||
evt.SetClientData( this );
|
evt.SetClientData( this );
|
||||||
evt.SetInt( type );
|
evt.SetInt( type );
|
||||||
|
evt.SetExtraLong( m_resume_when_done );
|
||||||
wxGetApp().AddPendingEvent( evt );
|
wxGetApp().AddPendingEvent( evt );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +128,7 @@ protected:
|
||||||
{
|
{
|
||||||
_parent::OnStart();
|
_parent::OnStart();
|
||||||
++sys_resume_lock;
|
++sys_resume_lock;
|
||||||
CoreThread.Pause();
|
m_resume_when_done = CoreThread.Pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteTaskInThread()
|
void ExecuteTaskInThread()
|
||||||
|
@ -122,43 +143,6 @@ protected:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// StateThread_Thaw
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
class StateThread_Thaw : public _BaseStateThread
|
|
||||||
{
|
|
||||||
typedef _BaseStateThread _parent;
|
|
||||||
|
|
||||||
public:
|
|
||||||
StateThread_Thaw( FnType_OnThreadComplete* onFinished ) : _BaseStateThread( "Thaw", onFinished ) { }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void OnStart()
|
|
||||||
{
|
|
||||||
_parent::OnStart();
|
|
||||||
|
|
||||||
if( state_buffer.IsDisposed() )
|
|
||||||
{
|
|
||||||
state_buffer_lock.Release();
|
|
||||||
throw Exception::RuntimeError( "ThawState request made, but no valid state exists!" );
|
|
||||||
}
|
|
||||||
|
|
||||||
++sys_resume_lock;
|
|
||||||
CoreThread.Pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecuteTaskInThread()
|
|
||||||
{
|
|
||||||
memLoadingState( state_buffer ).FreezeAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnCleanupInThread()
|
|
||||||
{
|
|
||||||
SendFinishEvent( StateThreadAction_Restore );
|
|
||||||
_parent::OnCleanupInThread();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// StateThread_ZipToDisk
|
// StateThread_ZipToDisk
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -171,14 +155,15 @@ protected:
|
||||||
gzFile m_gzfp;
|
gzFile m_gzfp;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StateThread_ZipToDisk( FnType_OnThreadComplete* onFinished, const wxString& file ) :
|
StateThread_ZipToDisk( FnType_OnThreadComplete* onFinished, bool resume_done, const wxString& file )
|
||||||
_BaseStateThread( "ZipToDisk", onFinished )
|
: _BaseStateThread( "ZipToDisk", onFinished )
|
||||||
, m_filename( file )
|
, m_filename( file )
|
||||||
, m_gzfp( NULL )
|
|
||||||
{
|
{
|
||||||
|
m_gzfp = NULL;
|
||||||
|
m_resume_when_done = resume_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
~StateThread_ZipToDisk() throw()
|
virtual ~StateThread_ZipToDisk() throw()
|
||||||
{
|
{
|
||||||
if( m_gzfp != NULL ) gzclose( m_gzfp );
|
if( m_gzfp != NULL ) gzclose( m_gzfp );
|
||||||
}
|
}
|
||||||
|
@ -232,15 +217,16 @@ protected:
|
||||||
bool m_finished;
|
bool m_finished;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StateThread_UnzipFromDisk( FnType_OnThreadComplete* onFinished, const wxString& file ) :
|
StateThread_UnzipFromDisk( FnType_OnThreadComplete* onFinished, bool resume_done, const wxString& file )
|
||||||
_BaseStateThread( "UnzipFromDisk", onFinished )
|
: _BaseStateThread( "UnzipFromDisk", onFinished )
|
||||||
, m_filename( file )
|
, m_filename( file )
|
||||||
, m_gzfp( NULL )
|
|
||||||
, m_finished( false )
|
|
||||||
{
|
{
|
||||||
|
m_gzfp = NULL;
|
||||||
|
m_finished = false;
|
||||||
|
m_resume_when_done = resume_done;
|
||||||
}
|
}
|
||||||
|
|
||||||
~StateThread_UnzipFromDisk() throw()
|
virtual ~StateThread_UnzipFromDisk() throw()
|
||||||
{
|
{
|
||||||
if( m_gzfp != NULL ) gzclose( m_gzfp );
|
if( m_gzfp != NULL ) gzclose( m_gzfp );
|
||||||
}
|
}
|
||||||
|
@ -297,32 +283,17 @@ void Pcsx2App::OnFreezeThreadFinished( wxCommandEvent& evt )
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fn_tmp != NULL ) fn_tmp( evt );
|
if( fn_tmp != NULL ) fn_tmp( evt );
|
||||||
|
|
||||||
//m_evtsrc_FreezeThreadFinished.Dispatch( evt );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnFinished_Resume( const wxCommandEvent& evt )
|
static void OnFinished_Resume( const wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
if( evt.GetInt() == StateThreadAction_Restore )
|
CoreThread.RecoverState();
|
||||||
{
|
if( evt.GetExtraLong() ) CoreThread.Resume();
|
||||||
// Successfully restored state, so remove the copy. Don't remove it sooner
|
|
||||||
// because the thread may have failed with some exception/error.
|
|
||||||
|
|
||||||
state_buffer.Dispose();
|
|
||||||
SysClearExecutionCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreThread.Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnFinished_Dispose( const wxCommandEvent& evt )
|
|
||||||
{
|
|
||||||
state_buffer.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static wxString zip_dest_filename;
|
static wxString zip_dest_filename;
|
||||||
|
|
||||||
void OnFinished_ZipToDisk( const wxCommandEvent& evt )
|
static void OnFinished_ZipToDisk( const wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
if( !pxAssertDev( evt.GetInt() == StateThreadAction_Create, "Unexpected StateThreadAction value, aborting save." ) ) return;
|
if( !pxAssertDev( evt.GetInt() == StateThreadAction_Create, "Unexpected StateThreadAction value, aborting save." ) ) return;
|
||||||
|
|
||||||
|
@ -331,21 +302,13 @@ void OnFinished_ZipToDisk( const wxCommandEvent& evt )
|
||||||
Console.Warning( "Cannot save state to disk: empty filename specified." );
|
Console.Warning( "Cannot save state to disk: empty filename specified." );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 2: Record to disk!!
|
// Phase 2: Record to disk!!
|
||||||
(new StateThread_ZipToDisk( OnFinished_Dispose, zip_dest_filename ))->Start();
|
(new StateThread_ZipToDisk( NULL, !!evt.GetExtraLong(), zip_dest_filename ))->Start();
|
||||||
|
|
||||||
CoreThread.Resume();
|
CoreThread.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnFinished_Restore( const wxCommandEvent& evt )
|
|
||||||
{
|
|
||||||
if( !pxAssertDev( evt.GetInt() == StateThreadAction_UnzipFromDisk, "Unexpected StateThreadAction value, aborting restore." ) ) return;
|
|
||||||
|
|
||||||
// Phase 2: Restore over existing VM state!!
|
|
||||||
(new StateThread_Thaw( OnFinished_Resume ))->Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =====================================================================================================
|
// =====================================================================================================
|
||||||
// StateCopy Public Interface
|
// StateCopy Public Interface
|
||||||
|
@ -362,8 +325,8 @@ void StateCopy_SaveToFile( const wxString& file )
|
||||||
void StateCopy_LoadFromFile( const wxString& file )
|
void StateCopy_LoadFromFile( const wxString& file )
|
||||||
{
|
{
|
||||||
if( state_buffer_lock.IsLocked() ) return;
|
if( state_buffer_lock.IsLocked() ) return;
|
||||||
CoreThread.Pause();
|
bool resume_when_done = CoreThread.Pause();
|
||||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
(new StateThread_UnzipFromDisk( OnFinished_Resume, resume_when_done, file ))->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saves recovery state info to the given saveslot, or saves the active emulation state
|
// Saves recovery state info to the given saveslot, or saves the active emulation state
|
||||||
|
@ -394,13 +357,13 @@ void StateCopy_LoadFromSlot( uint slot )
|
||||||
Console.WriteLn( Color_StrongGreen, "Loading savestate from slot %d...", slot );
|
Console.WriteLn( Color_StrongGreen, "Loading savestate from slot %d...", slot );
|
||||||
Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", file.c_str() );
|
Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", file.c_str() );
|
||||||
|
|
||||||
CoreThread.Pause();
|
bool resume_when_done = CoreThread.Pause();
|
||||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
(new StateThread_UnzipFromDisk( OnFinished_Resume, resume_when_done, file ))->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StateCopy_IsValid()
|
bool StateCopy_IsValid()
|
||||||
{
|
{
|
||||||
return !state_buffer.IsDisposed();
|
return !state_buffer.IsDisposed();
|
||||||
}
|
}
|
||||||
|
|
||||||
const SafeArray<u8>* StateCopy_GetBuffer()
|
const SafeArray<u8>* StateCopy_GetBuffer()
|
||||||
|
@ -412,20 +375,45 @@ const SafeArray<u8>* StateCopy_GetBuffer()
|
||||||
void StateCopy_FreezeToMem()
|
void StateCopy_FreezeToMem()
|
||||||
{
|
{
|
||||||
if( state_buffer_lock.IsLocked() ) return;
|
if( state_buffer_lock.IsLocked() ) return;
|
||||||
(new StateThread_Freeze( OnFinished_Restore ))->Start();
|
(new StateThread_Freeze( OnFinished_Resume ))->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateCopy_ThawFromMem()
|
static void _acquire_and_block()
|
||||||
{
|
{
|
||||||
if( state_buffer_lock.IsLocked() ) return;
|
if( state_buffer_lock.TryAcquire() ) return;
|
||||||
new StateThread_Thaw( OnFinished_Restore );
|
|
||||||
|
/*
|
||||||
|
// If the state buffer is locked and we're being called from the main thread then we need
|
||||||
|
// to cancel the current action. This is needed because state_buffer_lock is only updated
|
||||||
|
// from events handled on the main thread.
|
||||||
|
|
||||||
|
if( wxThread::IsMain() )
|
||||||
|
throw Exception::CancelEvent( "Blocking ThawFromMem canceled due to existing state buffer lock." );
|
||||||
|
else*/
|
||||||
|
{
|
||||||
|
pxAssume( current_state_thread != NULL );
|
||||||
|
do {
|
||||||
|
current_state_thread->Block();
|
||||||
|
wxGetApp().ProcessPendingEvents(); // Trying this for now, may or may not work due to recursive pitfalls (see above)
|
||||||
|
} while ( !state_buffer_lock.TryAcquire() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void State_ThawFromMem_Blocking()
|
void StateCopy_FreezeToMem_Blocking()
|
||||||
{
|
{
|
||||||
if( !state_buffer_lock.TryAcquire() )
|
_acquire_and_block();
|
||||||
|
|
||||||
|
memSavingState( state_buffer ).FreezeAll();
|
||||||
|
state_buffer_lock.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copies the saved state into the active VM, and automatically free's the saved state data.
|
||||||
|
void StateCopy_ThawFromMem_Blocking()
|
||||||
|
{
|
||||||
|
_acquire_and_block();
|
||||||
|
|
||||||
memLoadingState( state_buffer ).FreezeAll();
|
memLoadingState( state_buffer ).FreezeAll();
|
||||||
|
state_buffer.Dispose();
|
||||||
state_buffer_lock.Release();
|
state_buffer_lock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,3 +427,4 @@ bool StateCopy_IsBusy()
|
||||||
{
|
{
|
||||||
return state_buffer_lock.IsLocked();
|
return state_buffer_lock.IsLocked();
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,9 @@ public:
|
||||||
extern bool StateCopy_IsValid();
|
extern bool StateCopy_IsValid();
|
||||||
|
|
||||||
extern void StateCopy_FreezeToMem();
|
extern void StateCopy_FreezeToMem();
|
||||||
extern void StateCopy_ThawFromMem();
|
extern void StateCopy_FreezeToMem_Blocking();
|
||||||
|
extern void StateCopy_ThawFromMem_Blocking();
|
||||||
|
|
||||||
extern void StateCopy_SaveToFile( const wxString& file );
|
extern void StateCopy_SaveToFile( const wxString& file );
|
||||||
extern void StateCopy_LoadFromFile( const wxString& file );
|
extern void StateCopy_LoadFromFile( const wxString& file );
|
||||||
extern void StateCopy_SaveToSlot( uint num );
|
extern void StateCopy_SaveToSlot( uint num );
|
||||||
|
|
|
@ -57,7 +57,7 @@ TraceLogFilters& SetTraceConfig()
|
||||||
|
|
||||||
|
|
||||||
// This function should be called once during program execution.
|
// This function should be called once during program execution.
|
||||||
void SysDetect()
|
void SysLogMachineCaps()
|
||||||
{
|
{
|
||||||
Console.WriteLn( Color_StrongGreen, "PCSX2 %d.%d.%d.r%d %s - compiled on " __DATE__, PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo,
|
Console.WriteLn( Color_StrongGreen, "PCSX2 %d.%d.%d.r%d %s - compiled on " __DATE__, PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo,
|
||||||
SVN_REV, SVN_MODS ? "(modded)" : ""
|
SVN_REV, SVN_MODS ? "(modded)" : ""
|
||||||
|
@ -66,8 +66,6 @@ void SysDetect()
|
||||||
Console.WriteLn( "Savestate version: 0x%x", g_SaveVersion);
|
Console.WriteLn( "Savestate version: 0x%x", g_SaveVersion);
|
||||||
Console.Newline();
|
Console.Newline();
|
||||||
|
|
||||||
cpudetectInit();
|
|
||||||
|
|
||||||
Console.WriteLn( Color_StrongBlack, "x86-32 Init:" );
|
Console.WriteLn( Color_StrongBlack, "x86-32 Init:" );
|
||||||
|
|
||||||
Console.Indent().WriteLn(
|
Console.Indent().WriteLn(
|
||||||
|
@ -149,13 +147,15 @@ CpuInitializer< CpuType >::CpuInitializer()
|
||||||
}
|
}
|
||||||
catch( Exception::RuntimeError& ex )
|
catch( Exception::RuntimeError& ex )
|
||||||
{
|
{
|
||||||
Console.Error( L"MicroVU0 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
Console.Error( L"CPU provider error:\n\t" + ex.FormatDiagnosticMessage() );
|
||||||
MyCpu->Shutdown();
|
if( MyCpu )
|
||||||
|
MyCpu = NULL;
|
||||||
}
|
}
|
||||||
catch( std::runtime_error& ex )
|
catch( std::runtime_error& ex )
|
||||||
{
|
{
|
||||||
Console.Error( L"MicroVU0 Recompiler Allocation Failed (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
|
Console.Error( L"CPU provider error (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
|
||||||
MyCpu->Shutdown();
|
if( MyCpu )
|
||||||
|
MyCpu = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ protected:
|
||||||
// implemented by the provisioning interface.
|
// implemented by the provisioning interface.
|
||||||
extern SysCoreAllocations& GetSysCoreAlloc();
|
extern SysCoreAllocations& GetSysCoreAlloc();
|
||||||
|
|
||||||
extern void SysDetect(); // Detects cpu type and fills cpuInfo structs.
|
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
|
||||||
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
||||||
//
|
//
|
||||||
|
|
||||||
class pxMessageBoxEvent;
|
class pxMessageBoxEvent;
|
||||||
|
class pxAssertionEvent;
|
||||||
|
|
||||||
namespace Msgbox
|
namespace Msgbox
|
||||||
{
|
{
|
||||||
|
@ -116,10 +117,9 @@ namespace Msgbox
|
||||||
extern bool YesNo( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_QUESTION );
|
extern bool YesNo( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_QUESTION );
|
||||||
|
|
||||||
extern int Assertion( const wxString& text, const wxString& stacktrace );
|
extern int Assertion( const wxString& text, const wxString& stacktrace );
|
||||||
extern void Except( const Exception::BaseException& src );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BEGIN_DECLARE_EVENT_TYPES()
|
BEGIN_DECLARE_EVENT_TYPES()
|
||||||
DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 )
|
DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 )
|
||||||
DECLARE_EVENT_TYPE( pxEVT_CallStackBox, -1 )
|
DECLARE_EVENT_TYPE( pxEVT_ASSERTION, -1 )
|
||||||
END_DECLARE_EVENT_TYPES()
|
END_DECLARE_EVENT_TYPES()
|
||||||
|
|
|
@ -56,6 +56,18 @@ void SysCoreThread::Cancel( bool isBlocking )
|
||||||
{
|
{
|
||||||
m_CoreCancelDamnit = true;
|
m_CoreCancelDamnit = true;
|
||||||
_parent::Cancel();
|
_parent::Cancel();
|
||||||
|
ReleaseResumeLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SysCoreThread::Cancel( const wxTimeSpan& span )
|
||||||
|
{
|
||||||
|
m_CoreCancelDamnit = true;
|
||||||
|
if( _parent::Cancel( span ) )
|
||||||
|
{
|
||||||
|
ReleaseResumeLock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysCoreThread::Start()
|
void SysCoreThread::Start()
|
||||||
|
@ -78,21 +90,26 @@ void SysCoreThread::Start()
|
||||||
void SysCoreThread::OnResumeReady()
|
void SysCoreThread::OnResumeReady()
|
||||||
{
|
{
|
||||||
if( m_resetVirtualMachine )
|
if( m_resetVirtualMachine )
|
||||||
{
|
m_hasValidState = false;
|
||||||
cpuReset();
|
|
||||||
m_resetVirtualMachine = false;
|
|
||||||
m_hasValidState = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !m_hasValidState )
|
if( !m_hasValidState )
|
||||||
m_resetRecompilers = true;
|
m_resetRecompilers = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tells the thread to recover from the in-memory state copy when it resumes. (thread must be
|
||||||
|
// resumed manually).
|
||||||
|
void SysCoreThread::RecoverState()
|
||||||
|
{
|
||||||
|
Pause();
|
||||||
|
m_resetVirtualMachine = true;
|
||||||
|
m_hasValidState = false;
|
||||||
|
}
|
||||||
|
|
||||||
void SysCoreThread::Reset()
|
void SysCoreThread::Reset()
|
||||||
{
|
{
|
||||||
Suspend();
|
Suspend();
|
||||||
m_resetVirtualMachine = true;
|
m_resetVirtualMachine = true;
|
||||||
m_hasValidState = false;
|
m_hasValidState = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function *will* reset the emulator in order to allow the specified elf file to
|
// This function *will* reset the emulator in order to allow the specified elf file to
|
||||||
|
@ -159,7 +176,8 @@ void SysCoreThread::ApplySettings( const Pcsx2Config& src )
|
||||||
|
|
||||||
ScopedCoreThreadPause sys_paused;
|
ScopedCoreThreadPause sys_paused;
|
||||||
|
|
||||||
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
|
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Recompiler != EmuConfig.Recompiler ) ||
|
||||||
|
( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
|
||||||
m_resetProfilers = ( src.Profiler != EmuConfig.Profiler );
|
m_resetProfilers = ( src.Profiler != EmuConfig.Profiler );
|
||||||
m_resetVsyncTimers = ( src.GS != EmuConfig.GS );
|
m_resetVsyncTimers = ( src.GS != EmuConfig.GS );
|
||||||
|
|
||||||
|
@ -213,10 +231,50 @@ struct ScopedBool_ClearOnError
|
||||||
void Success() { m_success = true; }
|
void Success() { m_success = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SysCoreThread::_reset_stuff_as_needed()
|
||||||
|
{
|
||||||
|
if( m_resetVirtualMachine || m_resetRecompilers || m_resetProfilers )
|
||||||
|
{
|
||||||
|
SysClearExecutionCache();
|
||||||
|
memBindConditionalHandlers();
|
||||||
|
m_resetRecompilers = false;
|
||||||
|
m_resetProfilers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_resetVirtualMachine )
|
||||||
|
{
|
||||||
|
cpuReset();
|
||||||
|
m_resetVirtualMachine = false;
|
||||||
|
m_resetRecompilers = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_resetVsyncTimers )
|
||||||
|
{
|
||||||
|
UpdateVSyncRate();
|
||||||
|
frameLimitReset();
|
||||||
|
m_resetVsyncTimers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetCPUState( EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVUMXCSR );
|
||||||
|
}
|
||||||
|
|
||||||
void SysCoreThread::CpuInitializeMess()
|
void SysCoreThread::CpuInitializeMess()
|
||||||
{
|
{
|
||||||
if( m_hasValidState ) return;
|
if( m_hasValidState ) return;
|
||||||
|
|
||||||
|
if( StateCopy_IsValid() )
|
||||||
|
{
|
||||||
|
// Automatic recovery system if a state exists in memory. This is executed here
|
||||||
|
// in order to ensure the plugins are in the proper (loaded/opened) state.
|
||||||
|
|
||||||
|
SysClearExecutionCache();
|
||||||
|
StateCopy_ThawFromMem_Blocking();
|
||||||
|
|
||||||
|
m_hasValidState = true;
|
||||||
|
m_resetVirtualMachine = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_reset_stuff_as_needed();
|
_reset_stuff_as_needed();
|
||||||
|
|
||||||
ScopedBool_ClearOnError sbcoe( m_hasValidState );
|
ScopedBool_ClearOnError sbcoe( m_hasValidState );
|
||||||
|
@ -262,24 +320,6 @@ void SysCoreThread::CpuInitializeMess()
|
||||||
sbcoe.Success();
|
sbcoe.Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysCoreThread::_reset_stuff_as_needed()
|
|
||||||
{
|
|
||||||
if( m_resetRecompilers || m_resetProfilers )
|
|
||||||
{
|
|
||||||
SysClearExecutionCache();
|
|
||||||
memBindConditionalHandlers();
|
|
||||||
m_resetRecompilers = false;
|
|
||||||
m_resetProfilers = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( m_resetVsyncTimers )
|
|
||||||
{
|
|
||||||
UpdateVSyncRate();
|
|
||||||
frameLimitReset();
|
|
||||||
m_resetVsyncTimers = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the VsyncInThread() if a valid keyEvent is pending and is unhandled by other
|
// Called by the VsyncInThread() if a valid keyEvent is pending and is unhandled by other
|
||||||
// PS2 core plugins.
|
// PS2 core plugins.
|
||||||
void SysCoreThread::DispatchKeyEventToUI( const keyEvent& evt )
|
void SysCoreThread::DispatchKeyEventToUI( const keyEvent& evt )
|
||||||
|
@ -315,10 +355,11 @@ void SysCoreThread::StateCheckInThread()
|
||||||
{
|
{
|
||||||
GetMTGS().RethrowException();
|
GetMTGS().RethrowException();
|
||||||
_parent::StateCheckInThread();
|
_parent::StateCheckInThread();
|
||||||
|
|
||||||
if( !m_hasValidState )
|
if( !m_hasValidState )
|
||||||
throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." );
|
throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." );
|
||||||
|
|
||||||
_reset_stuff_as_needed();
|
_reset_stuff_as_needed(); // kinda redundant but could catch unexpected threaded state changes...
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysCoreThread::ExecuteTaskInThread()
|
void SysCoreThread::ExecuteTaskInThread()
|
||||||
|
@ -330,9 +371,10 @@ void SysCoreThread::ExecuteTaskInThread()
|
||||||
m_mxcsr_saved.bitmask = _mm_getcsr();
|
m_mxcsr_saved.bitmask = _mm_getcsr();
|
||||||
|
|
||||||
PCSX2_PAGEFAULT_PROTECT {
|
PCSX2_PAGEFAULT_PROTECT {
|
||||||
StateCheckInThread();
|
do {
|
||||||
SetCPUState( EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVUMXCSR );
|
StateCheckInThread();
|
||||||
Cpu->Execute();
|
Cpu->Execute();
|
||||||
|
} while( true );
|
||||||
} PCSX2_PAGEFAULT_EXCEPT;
|
} PCSX2_PAGEFAULT_EXCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,8 +389,7 @@ void SysCoreThread::OnResumeInThread( bool isSuspended )
|
||||||
if( g_plugins != NULL )
|
if( g_plugins != NULL )
|
||||||
g_plugins->Open();
|
g_plugins->Open();
|
||||||
|
|
||||||
if( isSuspended )
|
CpuInitializeMess();
|
||||||
CpuInitializeMess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,22 +36,9 @@ SysThreadBase::~SysThreadBase() throw()
|
||||||
void SysThreadBase::Start()
|
void SysThreadBase::Start()
|
||||||
{
|
{
|
||||||
_parent::Start();
|
_parent::Start();
|
||||||
m_ExecMode = ExecMode_Closing;
|
|
||||||
|
|
||||||
Sleep( 1 );
|
Sleep( 1 );
|
||||||
|
|
||||||
if( !m_ResumeEvent.WaitWithoutYield( wxTimeSpan(0, 0, 1, 500) ) )
|
|
||||||
{
|
|
||||||
RethrowException();
|
|
||||||
if( pxAssertDev( m_ExecMode == ExecMode_Closing, "Unexpected thread status during SysThread startup." ) )
|
|
||||||
{
|
|
||||||
throw Exception::ThreadCreationError( *this,
|
|
||||||
L"Timeout occurred while attempting to start the '%s' thread.",
|
|
||||||
wxEmptyString
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pxAssertDev( (m_ExecMode == ExecMode_Closing) || (m_ExecMode == ExecMode_Closed),
|
pxAssertDev( (m_ExecMode == ExecMode_Closing) || (m_ExecMode == ExecMode_Closed),
|
||||||
"Unexpected thread status during SysThread startup."
|
"Unexpected thread status during SysThread startup."
|
||||||
);
|
);
|
||||||
|
@ -118,7 +105,7 @@ bool SysThreadBase::Suspend( bool isBlocking )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxAssertDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." );
|
pxAssumeDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." );
|
||||||
m_sem_event.Post();
|
m_sem_event.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +151,7 @@ bool SysThreadBase::Pause()
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pxAssertDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
|
pxAssumeDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
|
||||||
|
|
||||||
m_sem_event.Post();
|
m_sem_event.Post();
|
||||||
}
|
}
|
||||||
|
@ -247,7 +234,7 @@ void SysThreadBase::OnStartInThread()
|
||||||
{
|
{
|
||||||
m_RunningLock.Acquire();
|
m_RunningLock.Acquire();
|
||||||
_parent::OnStartInThread();
|
_parent::OnStartInThread();
|
||||||
m_ResumeEvent.Post();
|
m_ExecMode = ExecMode_Closing;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysThreadBase::OnCleanupInThread()
|
void SysThreadBase::OnCleanupInThread()
|
||||||
|
|
|
@ -20,22 +20,6 @@
|
||||||
|
|
||||||
using namespace Threading;
|
using namespace Threading;
|
||||||
|
|
||||||
|
|
||||||
#if !PCSX2_SEH
|
|
||||||
# include <setjmp.h>
|
|
||||||
|
|
||||||
// Platforms without SEH need to use SetJmp / LongJmp to deal with exiting the recompiled
|
|
||||||
// code execution pipelines in an efficient manner, since standard C++ exceptions cannot
|
|
||||||
// unwind across dynamically recompiled code.
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SetJmp_Dispatcher = 1,
|
|
||||||
SetJmp_Exit,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// ISysThread
|
// ISysThread
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -208,8 +192,10 @@ public:
|
||||||
virtual void ApplySettings( const Pcsx2Config& src );
|
virtual void ApplySettings( const Pcsx2Config& src );
|
||||||
virtual void OnResumeReady();
|
virtual void OnResumeReady();
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
virtual void RecoverState();
|
||||||
virtual void Cancel( bool isBlocking=true );
|
virtual void Cancel( bool isBlocking=true );
|
||||||
|
virtual bool Cancel( const wxTimeSpan& timeout );
|
||||||
|
|
||||||
bool HasValidState()
|
bool HasValidState()
|
||||||
{
|
{
|
||||||
return m_hasValidState;
|
return m_hasValidState;
|
||||||
|
|
|
@ -65,14 +65,12 @@ void __fastcall vu0ExecMicro(u32 addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VU0unknown() {
|
void VU0unknown() {
|
||||||
assert(0);
|
pxFailDev("Unknown VU micromode opcode called");
|
||||||
|
|
||||||
CPU_LOG("Unknown VU micromode opcode called");
|
CPU_LOG("Unknown VU micromode opcode called");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VU0regsunknown(_VURegsNum *VUregsn) {
|
void VU0regsunknown(_VURegsNum *VUregsn) {
|
||||||
assert(0);
|
pxFailDev("Unknown VU micromode opcode called");
|
||||||
|
|
||||||
CPU_LOG("Unknown VU micromode opcode called");
|
CPU_LOG("Unknown VU micromode opcode called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
// this boolean indicates to some generic logging facilities if the VU's registers
|
// this boolean indicates to some generic logging facilities if the VU's registers
|
||||||
// are valid for logging or not. (see DisVU1Micro.cpp, etc) [kinda hacky, might
|
// are valid for logging or not. (see DisVU1Micro.cpp, etc) [kinda hacky, might
|
||||||
// be removed in the future]
|
// be removed in the future]
|
||||||
bool IsInterpreter;
|
bool IsInterpreter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BaseCpuProvider()
|
BaseCpuProvider()
|
||||||
|
@ -105,6 +105,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BaseVUmicroCPU() {}
|
BaseVUmicroCPU() {}
|
||||||
|
virtual ~BaseVUmicroCPU() throw() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -115,6 +116,7 @@ class InterpVU0 : public BaseVUmicroCPU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InterpVU0();
|
InterpVU0();
|
||||||
|
virtual ~InterpVU0() throw() { Shutdown(); }
|
||||||
|
|
||||||
const char* GetShortName() const { return "intVU0"; }
|
const char* GetShortName() const { return "intVU0"; }
|
||||||
wxString GetLongName() const { return L"VU0 Interpreter"; }
|
wxString GetLongName() const { return L"VU0 Interpreter"; }
|
||||||
|
@ -132,6 +134,7 @@ class InterpVU1 : public BaseVUmicroCPU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InterpVU1();
|
InterpVU1();
|
||||||
|
virtual ~InterpVU1() throw() { Shutdown(); }
|
||||||
|
|
||||||
const char* GetShortName() const { return "intVU1"; }
|
const char* GetShortName() const { return "intVU1"; }
|
||||||
wxString GetLongName() const { return L"VU1 Interpreter"; }
|
wxString GetLongName() const { return L"VU1 Interpreter"; }
|
||||||
|
@ -152,6 +155,7 @@ class recMicroVU0 : public BaseVUmicroCPU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
recMicroVU0();
|
recMicroVU0();
|
||||||
|
virtual ~recMicroVU0() throw() { Shutdown(); }
|
||||||
|
|
||||||
const char* GetShortName() const { return "mVU0"; }
|
const char* GetShortName() const { return "mVU0"; }
|
||||||
wxString GetLongName() const { return L"microVU0 Recompiler"; }
|
wxString GetLongName() const { return L"microVU0 Recompiler"; }
|
||||||
|
@ -169,6 +173,7 @@ class recMicroVU1 : public BaseVUmicroCPU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
recMicroVU1();
|
recMicroVU1();
|
||||||
|
virtual ~recMicroVU1() throw() { Shutdown(); }
|
||||||
|
|
||||||
const char* GetShortName() const { return "mVU1"; }
|
const char* GetShortName() const { return "mVU1"; }
|
||||||
wxString GetLongName() const { return L"microVU1 Recompiler"; }
|
wxString GetLongName() const { return L"microVU1 Recompiler"; }
|
||||||
|
|
|
@ -130,9 +130,9 @@ static int __fastcall Vif0TransSTRow(u32 *data) // STROW
|
||||||
|
|
||||||
u32* pmem = &vif0Regs->r0 + (vif0.tag.addr << 2);
|
u32* pmem = &vif0Regs->r0 + (vif0.tag.addr << 2);
|
||||||
u32* pmem2 = g_vifmask.Row0 + vif0.tag.addr;
|
u32* pmem2 = g_vifmask.Row0 + vif0.tag.addr;
|
||||||
pxAssert(vif0.tag.addr < 4);
|
pxAssume(vif0.tag.addr < 4);
|
||||||
ret = min(4 - vif0.tag.addr, vif0.vifpacketsize);
|
ret = min(4 - vif0.tag.addr, vif0.vifpacketsize);
|
||||||
pxAssert(ret > 0);
|
pxAssume(ret > 0);
|
||||||
|
|
||||||
switch (ret)
|
switch (ret)
|
||||||
{
|
{
|
||||||
|
@ -752,7 +752,7 @@ void vif0Write32(u32 mem, u32 value)
|
||||||
case VIF0_R1:
|
case VIF0_R1:
|
||||||
case VIF0_R2:
|
case VIF0_R2:
|
||||||
case VIF0_R3:
|
case VIF0_R3:
|
||||||
pxAssert((mem&0xf) == 0);
|
pxAssume((mem&0xf) == 0);
|
||||||
g_vifmask.Row0[(mem>>4) & 3] = value;
|
g_vifmask.Row0[(mem>>4) & 3] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -760,7 +760,7 @@ void vif0Write32(u32 mem, u32 value)
|
||||||
case VIF0_C1:
|
case VIF0_C1:
|
||||||
case VIF0_C2:
|
case VIF0_C2:
|
||||||
case VIF0_C3:
|
case VIF0_C3:
|
||||||
pxAssert((mem&0xf) == 0);
|
pxAssume((mem&0xf) == 0);
|
||||||
g_vifmask.Col0[(mem>>4) & 3] = value;
|
g_vifmask.Col0[(mem>>4) & 3] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ static __forceinline void vif1mpgTransfer(u32 addr, u32 *data, int size)
|
||||||
fwrite(data, 1, size*4, f);
|
fwrite(data, 1, size*4, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}*/
|
}*/
|
||||||
pxAssert(VU1.Micro > 0);
|
pxAssume(VU1.Micro > 0);
|
||||||
if (memcmp(VU1.Micro + addr, data, size << 2))
|
if (memcmp(VU1.Micro + addr, data, size << 2))
|
||||||
{
|
{
|
||||||
CpuVU1->Clear(addr, size << 2); // Clear before writing! :/
|
CpuVU1->Clear(addr, size << 2); // Clear before writing! :/
|
||||||
|
@ -148,9 +148,9 @@ static int __fastcall Vif1TransSTRow(u32 *data) // STROW
|
||||||
|
|
||||||
u32* pmem = &vif1Regs->r0 + (vif1.tag.addr << 2);
|
u32* pmem = &vif1Regs->r0 + (vif1.tag.addr << 2);
|
||||||
u32* pmem2 = g_vifmask.Row1 + vif1.tag.addr;
|
u32* pmem2 = g_vifmask.Row1 + vif1.tag.addr;
|
||||||
pxAssert(vif1.tag.addr < 4);
|
pxAssume(vif1.tag.addr < 4);
|
||||||
ret = min(4 - vif1.tag.addr, vif1.vifpacketsize);
|
ret = min(4 - vif1.tag.addr, vif1.vifpacketsize);
|
||||||
pxAssert(ret > 0);
|
pxAssume(ret > 0);
|
||||||
|
|
||||||
switch (ret)
|
switch (ret)
|
||||||
{
|
{
|
||||||
|
@ -1143,7 +1143,7 @@ void vif1Write32(u32 mem, u32 value)
|
||||||
case VIF1_R1:
|
case VIF1_R1:
|
||||||
case VIF1_R2:
|
case VIF1_R2:
|
||||||
case VIF1_R3:
|
case VIF1_R3:
|
||||||
pxAssert((mem&0xf) == 0);
|
pxAssume((mem&0xf) == 0);
|
||||||
g_vifmask.Row1[(mem>>4) & 3] = value;
|
g_vifmask.Row1[(mem>>4) & 3] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1151,7 +1151,7 @@ void vif1Write32(u32 mem, u32 value)
|
||||||
case VIF1_C1:
|
case VIF1_C1:
|
||||||
case VIF1_C2:
|
case VIF1_C2:
|
||||||
case VIF1_C3:
|
case VIF1_C3:
|
||||||
pxAssert((mem&0xf) == 0);
|
pxAssume((mem&0xf) == 0);
|
||||||
g_vifmask.Col1[(mem>>4) & 3] = value;
|
g_vifmask.Col1[(mem>>4) & 3] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -283,9 +283,7 @@ template<const u32 VIFdmanum> u32 VIFalign(u32 *data, vifCode *v, u32 size)
|
||||||
vif = &vif1;
|
vif = &vif1;
|
||||||
vifRow = g_vifmask.Row1;
|
vifRow = g_vifmask.Row1;
|
||||||
}
|
}
|
||||||
#ifdef PCSX2_DEBUG
|
pxAssume(v->addr < memsize);
|
||||||
pxAssert(v->addr < memsize);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dest = (u32*)(VU->Mem + v->addr);
|
dest = (u32*)(VU->Mem + v->addr);
|
||||||
|
|
||||||
|
@ -476,9 +474,7 @@ template<const u32 VIFdmanum> void VIFunpack(u32 *data, vifCode *v, u32 size)
|
||||||
u32 tempsize = 0;
|
u32 tempsize = 0;
|
||||||
const u32 memlimit = vif_size(VIFdmanum);
|
const u32 memlimit = vif_size(VIFdmanum);
|
||||||
|
|
||||||
#ifdef PCSX2_DEBUG
|
pxDebugCode( u32 memsize = memlimit );
|
||||||
u32 memsize = memlimit;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_mm_prefetch((char*)data, _MM_HINT_NTA);
|
_mm_prefetch((char*)data, _MM_HINT_NTA);
|
||||||
|
|
||||||
|
@ -489,9 +485,7 @@ template<const u32 VIFdmanum> void VIFunpack(u32 *data, vifCode *v, u32 size)
|
||||||
vifMaskRegs = g_vif0Masks;
|
vifMaskRegs = g_vif0Masks;
|
||||||
vif = &vif0;
|
vif = &vif0;
|
||||||
vifRow = g_vifmask.Row0;
|
vifRow = g_vifmask.Row0;
|
||||||
#ifdef PCSX2_DEBUG
|
pxDebugCode( pxAssume(v->addr < memsize) );
|
||||||
pxAssert(v->addr < memsize);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -501,9 +495,7 @@ template<const u32 VIFdmanum> void VIFunpack(u32 *data, vifCode *v, u32 size)
|
||||||
vifMaskRegs = g_vif1Masks;
|
vifMaskRegs = g_vif1Masks;
|
||||||
vif = &vif1;
|
vif = &vif1;
|
||||||
vifRow = g_vifmask.Row1;
|
vifRow = g_vifmask.Row1;
|
||||||
#ifdef PCSX2_DEBUG
|
pxDebugCode( pxAssume(v->addr < memsize) );
|
||||||
pxAssert(v->addr < memsize);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = (u32*)(VU->Mem + v->addr);
|
dest = (u32*)(VU->Mem + v->addr);
|
||||||
|
@ -523,9 +515,7 @@ template<const u32 VIFdmanum> void VIFunpack(u32 *data, vifCode *v, u32 size)
|
||||||
|
|
||||||
size <<= 2;
|
size <<= 2;
|
||||||
|
|
||||||
#ifdef PCSX2_DEBUG
|
pxDebugCode( memsize = size );
|
||||||
memsize = size;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (vifRegs->cycle.cl >= vifRegs->cycle.wl) // skipping write
|
if (vifRegs->cycle.cl >= vifRegs->cycle.wl) // skipping write
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,6 @@ class AppCoreThread;
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
#include "System/SysThreads.h"
|
#include "System/SysThreads.h"
|
||||||
|
|
||||||
|
|
||||||
typedef void FnType_OnThreadComplete(const wxCommandEvent& evt);
|
typedef void FnType_OnThreadComplete(const wxCommandEvent& evt);
|
||||||
|
|
||||||
BEGIN_DECLARE_EVENT_TYPES()
|
BEGIN_DECLARE_EVENT_TYPES()
|
||||||
|
@ -151,14 +150,6 @@ enum MenuIdentifiers
|
||||||
MenuId_Config_ResetAll,
|
MenuId_Config_ResetAll,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DialogIdentifiers
|
|
||||||
{
|
|
||||||
DialogId_CoreSettings = 0x800,
|
|
||||||
DialogId_BiosSelector,
|
|
||||||
DialogId_LogOptions,
|
|
||||||
DialogId_About,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum AppEventType
|
enum AppEventType
|
||||||
{
|
{
|
||||||
// Maybe this will be expanded upon later..?
|
// Maybe this will be expanded upon later..?
|
||||||
|
@ -331,9 +322,9 @@ struct MsgboxEventResult
|
||||||
Semaphore WaitForMe;
|
Semaphore WaitForMe;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
MsgboxEventResult() :
|
MsgboxEventResult()
|
||||||
WaitForMe(), result( 0 )
|
|
||||||
{
|
{
|
||||||
|
result = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -406,7 +397,7 @@ public:
|
||||||
|
|
||||||
void PostPadKey( wxKeyEvent& evt );
|
void PostPadKey( wxKeyEvent& evt );
|
||||||
void PostMenuAction( MenuIdentifiers menu_id ) const;
|
void PostMenuAction( MenuIdentifiers menu_id ) const;
|
||||||
int ThreadedModalDialog( DialogIdentifiers dialogId );
|
int IssueModalDialog( const wxString& dlgName );
|
||||||
|
|
||||||
bool PrepForExit( bool canCancel );
|
bool PrepForExit( bool canCancel );
|
||||||
|
|
||||||
|
@ -532,6 +523,7 @@ public:
|
||||||
virtual bool Suspend( bool isBlocking=true );
|
virtual bool Suspend( bool isBlocking=true );
|
||||||
virtual void Resume();
|
virtual void Resume();
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
virtual void Cancel( bool isBlocking=true );
|
||||||
virtual void StateCheckInThread();
|
virtual void StateCheckInThread();
|
||||||
virtual void ApplySettings( const Pcsx2Config& src );
|
virtual void ApplySettings( const Pcsx2Config& src );
|
||||||
virtual void ChangeCdvdSource( CDVD_SourceType type );
|
virtual void ChangeCdvdSource( CDVD_SourceType type );
|
||||||
|
@ -610,6 +602,9 @@ public:
|
||||||
virtual ~SaveSinglePluginHelper() throw();
|
virtual ~SaveSinglePluginHelper() throw();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern pxDoAssertFnType AppDoAssert;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// External App-related Globals and Shortcuts
|
// External App-related Globals and Shortcuts
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -18,18 +18,27 @@
|
||||||
|
|
||||||
#include <wx/stackwalk.h>
|
#include <wx/stackwalk.h>
|
||||||
|
|
||||||
|
static wxString pxGetStackTrace( const FnChar_t* calledFrom )
|
||||||
static wxString pxGetStackTrace()
|
|
||||||
{
|
{
|
||||||
wxString stackTrace;
|
wxString stackTrace;
|
||||||
|
|
||||||
class StackDump : public wxStackWalker
|
class StackDump : public wxStackWalker
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
wxString m_stackTrace;
|
wxString m_stackTrace;
|
||||||
|
wxString m_srcFuncName;
|
||||||
|
bool m_ignoreDone;
|
||||||
|
int m_skipped;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StackDump() { }
|
StackDump( const FnChar_t* src_function_name )
|
||||||
|
{
|
||||||
|
if( src_function_name != NULL )
|
||||||
|
m_srcFuncName = fromUTF8(src_function_name);
|
||||||
|
|
||||||
|
m_ignoreDone = false;
|
||||||
|
m_skipped = 0;
|
||||||
|
}
|
||||||
|
|
||||||
const wxString& GetStackTrace() const { return m_stackTrace; }
|
const wxString& GetStackTrace() const { return m_stackTrace; }
|
||||||
|
|
||||||
|
@ -38,92 +47,108 @@ static wxString pxGetStackTrace()
|
||||||
{
|
{
|
||||||
wxString name( frame.GetName() );
|
wxString name( frame.GetName() );
|
||||||
if( name.IsEmpty() )
|
if( name.IsEmpty() )
|
||||||
|
{
|
||||||
name = wxsFormat( L"%p ", frame.GetAddress() );
|
name = wxsFormat( L"%p ", frame.GetAddress() );
|
||||||
|
}
|
||||||
|
/*else if( m_srcFuncName.IsEmpty() || m_srcFuncName == name )
|
||||||
|
{
|
||||||
|
// FIXME: This logic isn't reliable yet.
|
||||||
|
// It's possible for our debug information to not match the function names returned by
|
||||||
|
// __pxFUNCTION__ (might happen in linux a lot, and could happen in win32 due to
|
||||||
|
// inlining on Dev aserts). The better approach is a system the queues up all the
|
||||||
|
// stacktrace info in individual wxStrings, and does a two-pass check -- first pass
|
||||||
|
// for the function name and, if not found, a second pass that just skips the first
|
||||||
|
// few stack entries.
|
||||||
|
|
||||||
|
// It's important we only walk the stack once because Linux (argh, always linux!) has
|
||||||
|
// a really god aweful slow stack walker.
|
||||||
|
|
||||||
|
// I'm not doing it right now because I've worked on this mess enough for one week. --air
|
||||||
|
|
||||||
m_stackTrace += wxString::Format( L"[%02d] %-46s ",
|
m_ignoreDone = true;
|
||||||
wx_truncate_cast(int, frame.GetLevel()), name.c_str()
|
}
|
||||||
|
|
||||||
|
if( !m_ignoreDone )
|
||||||
|
{
|
||||||
|
m_skipped++;
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//wxString briefName;
|
||||||
|
wxString essenName;
|
||||||
|
|
||||||
|
if( frame.HasSourceLocation() )
|
||||||
|
{
|
||||||
|
wxFileName wxfn(frame.GetFileName());
|
||||||
|
//briefName.Printf( L"(%s:%d)", wxfn.GetFullName().c_str(), frame.GetLine() );
|
||||||
|
|
||||||
|
wxfn.SetVolume( wxEmptyString );
|
||||||
|
int count = wxfn.GetDirCount();
|
||||||
|
for( int i=0; i<2; ++i )
|
||||||
|
wxfn.RemoveDir(0);
|
||||||
|
|
||||||
|
essenName.Printf( L"%s:%d", wxfn.GetFullPath().c_str(), frame.GetLine() );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stackTrace += wxString::Format( L"[%02d] %-44s %s\n",
|
||||||
|
frame.GetLevel()-m_skipped,
|
||||||
|
name.c_str(),
|
||||||
|
essenName.c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( frame.HasSourceLocation() )
|
|
||||||
m_stackTrace += wxsFormat( L"%s:%d", frame.GetFileName().c_str(), frame.GetLine() );
|
|
||||||
|
|
||||||
m_stackTrace += L'\n';
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// [TODO] : Replace this with a textbox dialog setup.
|
StackDump dump( calledFrom );
|
||||||
static const int maxLines = 20;
|
dump.Walk( 3 );
|
||||||
|
return dump.GetStackTrace();
|
||||||
StackDump dump;
|
|
||||||
dump.Walk(2, maxLines); // don't show OnAssert() call itself
|
|
||||||
stackTrace = dump.GetStackTrace();
|
|
||||||
|
|
||||||
const int count = stackTrace.Freq( L'\n' );
|
|
||||||
for ( int i = 0; i < count - maxLines; i++ )
|
|
||||||
stackTrace = stackTrace.BeforeLast( L'\n' );
|
|
||||||
|
|
||||||
return stackTrace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __threadlocal bool _reentrant_lock = false;
|
|
||||||
|
|
||||||
#ifdef __WXDEBUG__
|
#ifdef __WXDEBUG__
|
||||||
|
|
||||||
|
static __threadlocal int _reentrant_lock = 0;
|
||||||
|
|
||||||
// This override of wx's implementation provides thread safe assertion message reporting. If we aren't
|
// This override of wx's implementation provides thread safe assertion message reporting. If we aren't
|
||||||
// on the main gui thread then the assertion message box needs to be passed off to the main gui thread
|
// on the main gui thread then the assertion message box needs to be passed off to the main gui thread
|
||||||
// via messages.
|
// via messages.
|
||||||
void Pcsx2App::OnAssertFailure( const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg )
|
void Pcsx2App::OnAssertFailure( const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg )
|
||||||
{
|
{
|
||||||
// Used to allow the user to suppress future assertions during this application's session.
|
// Re-entrant assertions are bad mojo -- trap immediately.
|
||||||
static bool disableAsserts = false;
|
RecursionGuard guard( _reentrant_lock );
|
||||||
if( disableAsserts ) return;
|
if( guard.IsReentrant() ) wxTrap();
|
||||||
|
|
||||||
if( _reentrant_lock )
|
wxCharBuffer bleh( wxString(func).ToUTF8() );
|
||||||
|
if( AppDoAssert( DiagnosticOrigin( file, line, bleh, cond ), msg ) )
|
||||||
{
|
{
|
||||||
// Re-entrant assertions are bad mojo -- trap immediately.
|
|
||||||
wxTrap();
|
wxTrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_reentrant_lock = true;
|
#endif
|
||||||
|
|
||||||
wxString dbgmsg;
|
bool AppDoAssert( const DiagnosticOrigin& origin, const wxChar *msg )
|
||||||
dbgmsg.reserve( 2048 );
|
{
|
||||||
|
// Used to allow the user to suppress future assertions during this application's session.
|
||||||
|
static bool disableAsserts = false;
|
||||||
|
if( disableAsserts ) return false;
|
||||||
|
|
||||||
wxString message;
|
wxString trace( pxGetStackTrace(origin.function) );
|
||||||
if( msg == NULL )
|
wxString dbgmsg( origin.ToString( msg ) );
|
||||||
message = cond;
|
|
||||||
else
|
|
||||||
message.Printf( L"%s (%s)", msg, cond );
|
|
||||||
|
|
||||||
// make life easier for people using VC++ IDE by using this format, which allows double-click
|
|
||||||
// response times from the Output window...
|
|
||||||
dbgmsg.Printf( L"%s(%d) : assertion failed%s%s: %s\n", file, line,
|
|
||||||
(func==NULL) ? wxEmptyString : L" in ",
|
|
||||||
(func==NULL) ? wxEmptyString : func,
|
|
||||||
message.c_str()
|
|
||||||
);
|
|
||||||
|
|
||||||
wxString trace( L"Call stack:\n" + pxGetStackTrace() );
|
|
||||||
|
|
||||||
wxMessageOutputDebug().Printf( dbgmsg );
|
wxMessageOutputDebug().Printf( dbgmsg );
|
||||||
|
|
||||||
Console.Error( dbgmsg );
|
Console.Error( dbgmsg );
|
||||||
Console.WriteLn( trace );
|
Console.WriteLn( trace );
|
||||||
|
|
||||||
int retval = Msgbox::Assertion( dbgmsg, trace );
|
wxString windowmsg( L"Assertion failed: " );
|
||||||
|
if( msg != NULL )
|
||||||
switch( retval )
|
windowmsg += msg;
|
||||||
{
|
else if( origin.condition != NULL )
|
||||||
case wxID_YES:
|
windowmsg += origin.condition;
|
||||||
wxTrap();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case wxID_NO: break;
|
|
||||||
|
|
||||||
case wxID_CANCEL: // ignores future assertions.
|
|
||||||
disableAsserts = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_reentrant_lock = false;
|
int retval = Msgbox::Assertion( windowmsg, dbgmsg + L"\nStacktrace:\n" + trace );
|
||||||
|
|
||||||
|
if( retval == wxID_YES ) return true;
|
||||||
|
if( retval == wxID_IGNORE ) disableAsserts = true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -312,7 +312,7 @@ AppConfig::AppConfig()
|
||||||
, DeskTheme( L"default" )
|
, DeskTheme( L"default" )
|
||||||
{
|
{
|
||||||
LanguageId = wxLANGUAGE_DEFAULT;
|
LanguageId = wxLANGUAGE_DEFAULT;
|
||||||
RecentFileCount = 6;
|
RecentIsoCount = 12;
|
||||||
Listbook_ImageSize = 32;
|
Listbook_ImageSize = 32;
|
||||||
Toolbar_ImageSize = 24;
|
Toolbar_ImageSize = 24;
|
||||||
Toolbar_ShowLabels = true;
|
Toolbar_ShowLabels = true;
|
||||||
|
@ -378,7 +378,7 @@ void AppConfig::LoadSaveRootItems( IniInterface& ini )
|
||||||
IniEntry( MainGuiPosition );
|
IniEntry( MainGuiPosition );
|
||||||
IniEntry( SettingsTabName );
|
IniEntry( SettingsTabName );
|
||||||
ini.EnumEntry( L"LanguageId", LanguageId, NULL, defaults.LanguageId );
|
ini.EnumEntry( L"LanguageId", LanguageId, NULL, defaults.LanguageId );
|
||||||
IniEntry( RecentFileCount );
|
IniEntry( RecentIsoCount );
|
||||||
IniEntry( DeskTheme );
|
IniEntry( DeskTheme );
|
||||||
IniEntry( Listbook_ImageSize );
|
IniEntry( Listbook_ImageSize );
|
||||||
IniEntry( Toolbar_ImageSize );
|
IniEntry( Toolbar_ImageSize );
|
||||||
|
|
|
@ -154,7 +154,7 @@ public:
|
||||||
// Current language in use (correlates to a wxWidgets wxLANGUAGE specifier)
|
// Current language in use (correlates to a wxWidgets wxLANGUAGE specifier)
|
||||||
wxLanguage LanguageId;
|
wxLanguage LanguageId;
|
||||||
|
|
||||||
int RecentFileCount; // number of files displayed in the Recent Isos list.
|
int RecentIsoCount; // number of files displayed in the Recent Isos list.
|
||||||
|
|
||||||
// String value describing the desktop theme to use for pcsk2 (icons and background images)
|
// String value describing the desktop theme to use for pcsk2 (icons and background images)
|
||||||
// The theme name is used to look up files in the themes folder (relative to the executable).
|
// The theme name is used to look up files in the themes folder (relative to the executable).
|
||||||
|
|
|
@ -28,6 +28,16 @@ AppCoreThread::AppCoreThread() : SysCoreThread()
|
||||||
|
|
||||||
AppCoreThread::~AppCoreThread() throw()
|
AppCoreThread::~AppCoreThread() throw()
|
||||||
{
|
{
|
||||||
|
AppCoreThread::Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppCoreThread::Cancel( bool isBlocking )
|
||||||
|
{
|
||||||
|
if( !_parent::Cancel( wxTimeSpan( 0,0,1,0 ) ) )
|
||||||
|
{
|
||||||
|
// Possible deadlock!
|
||||||
|
throw Exception::ThreadTimedOut( this );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppCoreThread::Reset()
|
void AppCoreThread::Reset()
|
||||||
|
|
|
@ -45,6 +45,32 @@ namespace Exception
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CpuCheckSSE2()
|
||||||
|
{
|
||||||
|
if( x86caps.hasStreamingSIMD2Extensions ) return;
|
||||||
|
|
||||||
|
// Only check once per process session:
|
||||||
|
static bool checked = false;
|
||||||
|
if( checked ) return;
|
||||||
|
checked = true;
|
||||||
|
|
||||||
|
wxDialogWithHelpers exconf( NULL, _("PCSX2 - SSE2 Recommended"), wxVERTICAL );
|
||||||
|
|
||||||
|
exconf += exconf.Heading( pxE( ".Error:Startup:NoSSE2",
|
||||||
|
L"Warning: Your computer does not support SSE2, which is required by many PCSX2 recompilers and plugins. "
|
||||||
|
L"Your options will be limited and emulation will be *very* slow." )
|
||||||
|
);
|
||||||
|
|
||||||
|
pxIssueConfirmation( exconf, MsgButtons().OK(), L"Error:Startup:NoSSE2" );
|
||||||
|
|
||||||
|
// Auto-disable anything that needs SSE2:
|
||||||
|
|
||||||
|
g_Conf->EmuOptions.Cpu.Recompiler.EnableEE = false;
|
||||||
|
g_Conf->EmuOptions.Cpu.Recompiler.EnableVU0 = false;
|
||||||
|
g_Conf->EmuOptions.Cpu.Recompiler.EnableVU1 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Pcsx2App::OpenWizardConsole()
|
void Pcsx2App::OpenWizardConsole()
|
||||||
{
|
{
|
||||||
if( !IsDebugBuild ) return;
|
if( !IsDebugBuild ) return;
|
||||||
|
@ -81,8 +107,7 @@ void Pcsx2App::ReadUserModeSettings()
|
||||||
|
|
||||||
if (IOP_ENABLE_SIF_HACK == 1)
|
if (IOP_ENABLE_SIF_HACK == 1)
|
||||||
{
|
{
|
||||||
wxDialogWithHelpers hackedVersion( NULL, wxID_ANY, _("It will devour your young! - PCSX2 Shub-Niggurath edition"), false );
|
wxDialogWithHelpers hackedVersion( NULL, _("It will devour your young! - PCSX2 Shub-Niggurath edition"), wxVERTICAL );
|
||||||
hackedVersion.SetIdealWidth( 575 );
|
|
||||||
|
|
||||||
hackedVersion.SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
hackedVersion.SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||||
hackedVersion += new pxStaticText( &hackedVersion,
|
hackedVersion += new pxStaticText( &hackedVersion,
|
||||||
|
@ -92,8 +117,6 @@ void Pcsx2App::ReadUserModeSettings()
|
||||||
);
|
);
|
||||||
|
|
||||||
hackedVersion += new wxButton( &hackedVersion, wxID_OK ) | pxSizerFlags::StdCenter();
|
hackedVersion += new wxButton( &hackedVersion, wxID_OK ) | pxSizerFlags::StdCenter();
|
||||||
hackedVersion.Fit();
|
|
||||||
hackedVersion.CentreOnScreen();
|
|
||||||
hackedVersion.ShowModal();
|
hackedVersion.ShowModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,8 +124,7 @@ void Pcsx2App::ReadUserModeSettings()
|
||||||
{
|
{
|
||||||
// Pre-Alpha Warning! Why didn't I think to add this sooner?!
|
// Pre-Alpha Warning! Why didn't I think to add this sooner?!
|
||||||
|
|
||||||
wxDialogWithHelpers preAlpha( NULL, wxID_ANY, _("It might devour your kittens! - PCSX2 0.9.7 Pre-Alpha"), false );
|
wxDialogWithHelpers preAlpha( NULL, _("It might devour your kittens! - PCSX2 0.9.7 Pre-Alpha"), wxVERTICAL );
|
||||||
preAlpha.SetIdealWidth( 575 );
|
|
||||||
|
|
||||||
preAlpha.SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
preAlpha.SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||||
preAlpha += new pxStaticText( &preAlpha,
|
preAlpha += new pxStaticText( &preAlpha,
|
||||||
|
@ -113,8 +135,6 @@ void Pcsx2App::ReadUserModeSettings()
|
||||||
);
|
);
|
||||||
|
|
||||||
preAlpha += new wxButton( &preAlpha, wxID_OK ) | pxSizerFlags::StdCenter();
|
preAlpha += new wxButton( &preAlpha, wxID_OK ) | pxSizerFlags::StdCenter();
|
||||||
preAlpha.Fit();
|
|
||||||
preAlpha.CentreOnScreen();
|
|
||||||
preAlpha.ShowModal();
|
preAlpha.ShowModal();
|
||||||
|
|
||||||
// first time startup, so give the user the choice of user mode:
|
// first time startup, so give the user the choice of user mode:
|
||||||
|
@ -243,6 +263,15 @@ typedef void (wxEvtHandler::*pxMessageBoxEventFunction)(pxMessageBoxEvent&);
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
bool Pcsx2App::OnInit()
|
bool Pcsx2App::OnInit()
|
||||||
{
|
{
|
||||||
|
#define pxMessageBoxEventThing(func) \
|
||||||
|
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxMessageBoxEventFunction, &func )
|
||||||
|
|
||||||
|
Connect( pxEVT_MSGBOX, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) );
|
||||||
|
Connect( pxEVT_ASSERTION, pxMessageBoxEventThing( Pcsx2App::OnMessageBox ) );
|
||||||
|
Connect( pxEVT_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||||
|
|
||||||
|
pxDoAssert = AppDoAssert;
|
||||||
|
|
||||||
g_Conf = new AppConfig();
|
g_Conf = new AppConfig();
|
||||||
EnableAllLogging();
|
EnableAllLogging();
|
||||||
|
|
||||||
|
@ -253,12 +282,6 @@ bool Pcsx2App::OnInit()
|
||||||
m_StderrRedirHandle = NewPipeRedir(stderr);
|
m_StderrRedirHandle = NewPipeRedir(stderr);
|
||||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
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_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
|
||||||
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
|
Connect( pxEVT_ReloadPlugins, wxCommandEventHandler( Pcsx2App::OnReloadPlugins ) );
|
||||||
Connect( pxEVT_SysExecute, wxCommandEventHandler( Pcsx2App::OnSysExecute ) );
|
Connect( pxEVT_SysExecute, wxCommandEventHandler( Pcsx2App::OnSysExecute ) );
|
||||||
|
|
||||||
|
@ -286,9 +309,21 @@ bool Pcsx2App::OnInit()
|
||||||
|
|
||||||
m_Resources = new pxAppResources();
|
m_Resources = new pxAppResources();
|
||||||
|
|
||||||
|
cpudetectInit();
|
||||||
|
|
||||||
|
if( !x86caps.hasMultimediaExtensions )
|
||||||
|
{
|
||||||
|
// Note: due to memcpy_fast, we need minimum MMX even for interpreters. This will
|
||||||
|
// hopefully change later once we have a dynamically recompiled memcpy.
|
||||||
|
Msgbox::Alert( _("PCSX2 requires cpu with MMX instruction to run. Press OK to close."), _("PCSX2 - MMX Required") );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ReadUserModeSettings();
|
ReadUserModeSettings();
|
||||||
AppConfig_OnChangedSettingsFolder();
|
AppConfig_OnChangedSettingsFolder();
|
||||||
|
|
||||||
|
CpuCheckSSE2();
|
||||||
|
|
||||||
m_MainFrame = new MainEmuFrame( NULL, L"PCSX2" );
|
m_MainFrame = new MainEmuFrame( NULL, L"PCSX2" );
|
||||||
m_MainFrame->PushEventHandler( &GetRecentIsoList() );
|
m_MainFrame->PushEventHandler( &GetRecentIsoList() );
|
||||||
|
|
||||||
|
@ -307,7 +342,8 @@ bool Pcsx2App::OnInit()
|
||||||
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
|
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
|
||||||
m_MainFrame->Show();
|
m_MainFrame->Show();
|
||||||
|
|
||||||
SysDetect();
|
SysLogMachineCaps();
|
||||||
|
|
||||||
AppApplySettings();
|
AppApplySettings();
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
|
@ -317,47 +353,72 @@ bool Pcsx2App::OnInit()
|
||||||
|
|
||||||
m_CoreAllocs = new SysCoreAllocations();
|
m_CoreAllocs = new SysCoreAllocations();
|
||||||
|
|
||||||
|
|
||||||
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
|
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
|
||||||
{
|
{
|
||||||
// HadSomeFailures only returns 'true' if an *enabled* cpu type fails to init. If
|
// HadSomeFailures only returns 'true' if an *enabled* cpu type fails to init. If
|
||||||
// the user already has all interps configured, for example, then no point in
|
// the user already has all interps configured, for example, then no point in
|
||||||
// popping up this dialog.
|
// popping up this dialog.
|
||||||
|
|
||||||
|
wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)"), wxVERTICAL );
|
||||||
|
|
||||||
// TODO : This should be redone using the ExtensibleConfirmation, and a sub-window
|
exconf += 12;
|
||||||
// (static text or something with a vertical scrollbar).
|
exconf += exconf.Heading( pxE( ".Error:RecompilerInit",
|
||||||
|
L"Warning: Some of the configured PS2 recompilers failed to initialize and will not be available for this session:\n" )
|
||||||
|
);
|
||||||
|
|
||||||
wxString message( _("The following cpu recompilers failed to initialize and will not be available:\n\n") );
|
wxTextCtrl* scrollableTextArea = new wxTextCtrl(
|
||||||
|
&exconf, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||||
|
wxTE_READONLY | wxTE_MULTILINE | wxTE_WORDWRAP
|
||||||
|
);
|
||||||
|
|
||||||
|
exconf += scrollableTextArea | pxSizerFlags::StdExpand();
|
||||||
|
|
||||||
if( !m_CoreAllocs->IsRecAvailable_EE() )
|
if( !m_CoreAllocs->IsRecAvailable_EE() )
|
||||||
{
|
{
|
||||||
message += L"\t* R5900 (EE)\n";
|
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
|
||||||
|
|
||||||
|
g_Conf->EmuOptions.Recompiler.EnableEE = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !m_CoreAllocs->IsRecAvailable_IOP() )
|
if( !m_CoreAllocs->IsRecAvailable_IOP() )
|
||||||
{
|
{
|
||||||
message += L"\t* R3000A (IOP)\n";
|
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" );
|
||||||
|
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() )
|
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() )
|
||||||
{
|
{
|
||||||
message += L"\t* microVU0\n";
|
scrollableTextArea->AppendText( L"* microVU0\n\n" );
|
||||||
|
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = false;
|
||||||
|
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && m_CoreAllocs->IsRecAvailable_SuperVU0();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !m_CoreAllocs->IsRecAvailable_MicroVU1() )
|
if( !m_CoreAllocs->IsRecAvailable_MicroVU1() )
|
||||||
{
|
{
|
||||||
message += L"\t* microVU1\n";
|
scrollableTextArea->AppendText( L"* microVU1\n\n" );
|
||||||
|
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = false;
|
||||||
|
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && m_CoreAllocs->IsRecAvailable_SuperVU1();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !m_CoreAllocs->IsRecAvailable_SuperVU0() )
|
if( !m_CoreAllocs->IsRecAvailable_SuperVU0() )
|
||||||
{
|
{
|
||||||
message += L"\t* SuperVU0\n";
|
scrollableTextArea->AppendText( L"* SuperVU0\n\n" );
|
||||||
|
g_Conf->EmuOptions.Recompiler.UseMicroVU0 = m_CoreAllocs->IsRecAvailable_MicroVU0();
|
||||||
|
g_Conf->EmuOptions.Recompiler.EnableVU0 = g_Conf->EmuOptions.Recompiler.EnableVU0 && g_Conf->EmuOptions.Recompiler.UseMicroVU0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !m_CoreAllocs->IsRecAvailable_SuperVU1() )
|
if( !m_CoreAllocs->IsRecAvailable_SuperVU1() )
|
||||||
{
|
{
|
||||||
message += L"\t* SuperVU1\n";
|
scrollableTextArea->AppendText( L"* SuperVU1\n\n" );
|
||||||
|
g_Conf->EmuOptions.Recompiler.UseMicroVU1 = m_CoreAllocs->IsRecAvailable_MicroVU1();
|
||||||
|
g_Conf->EmuOptions.Recompiler.EnableVU1 = g_Conf->EmuOptions.Recompiler.EnableVU1 && g_Conf->EmuOptions.Recompiler.UseMicroVU1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exconf += new ModalButtonPanel( &exconf, MsgButtons().OK() ) | pxSizerFlags::StdCenter();
|
||||||
|
|
||||||
|
exconf.ShowModal();
|
||||||
|
|
||||||
// Failures can be SSE-related OR memory related. Should do per-cpu error reports instead...
|
// Failures can be SSE-related OR memory related. Should do per-cpu error reports instead...
|
||||||
|
|
||||||
/*message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
|
/*message += pxE( ".Popup Error:EmuCore:MemoryForRecs",
|
||||||
|
@ -367,8 +428,8 @@ bool Pcsx2App::OnInit()
|
||||||
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
|
L"Interpreters can be very slow, so don't get too excited. Press OK to continue or CANCEL to close PCSX2."
|
||||||
);*/
|
);*/
|
||||||
|
|
||||||
if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
|
//if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
|
||||||
return false;
|
// return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadPluginsPassive( NULL );
|
LoadPluginsPassive( NULL );
|
||||||
|
@ -408,13 +469,16 @@ void Pcsx2App::CleanupMess()
|
||||||
if( m_CorePlugins )
|
if( m_CorePlugins )
|
||||||
m_CorePlugins->Shutdown();
|
m_CorePlugins->Shutdown();
|
||||||
}
|
}
|
||||||
|
catch( Exception::ThreadTimedOut& ) { throw; }
|
||||||
|
catch( Exception::CancelEvent& ) { throw; }
|
||||||
catch( Exception::RuntimeError& ex )
|
catch( Exception::RuntimeError& ex )
|
||||||
{
|
{
|
||||||
// Handle runtime errors gracefully during shutdown. Mostly these are things
|
// Handle runtime errors gracefully during shutdown. Mostly these are things
|
||||||
// that we just don't care about by now, and just want to "get 'er done!" so
|
// that we just don't care about by now, and just want to "get 'er done!" so
|
||||||
// we can exit the app. ;)
|
// we can exit the app. ;)
|
||||||
|
|
||||||
Console.Error( ex.FormatDiagnosticMessage() );
|
Console.Error( L"Runtime exception handled during CleanupMess:\n" );
|
||||||
|
Console.Indent().Error( ex.FormatDiagnosticMessage() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notice: deleting the plugin manager (unloading plugins) here causes Lilypad to crash,
|
// Notice: deleting the plugin manager (unloading plugins) here causes Lilypad to crash,
|
||||||
|
@ -427,6 +491,8 @@ void Pcsx2App::CleanupMess()
|
||||||
|
|
||||||
while( wxGetLocale() != NULL )
|
while( wxGetLocale() != NULL )
|
||||||
delete wxGetLocale();
|
delete wxGetLocale();
|
||||||
|
|
||||||
|
pxDoAssert = pxAssertImpl_LogIt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pcsx2App::Pcsx2App()
|
Pcsx2App::Pcsx2App()
|
||||||
|
@ -441,6 +507,8 @@ Pcsx2App::Pcsx2App()
|
||||||
|
|
||||||
Pcsx2App::~Pcsx2App()
|
Pcsx2App::~Pcsx2App()
|
||||||
{
|
{
|
||||||
|
pxDoAssert = pxAssertImpl_LogIt;
|
||||||
|
|
||||||
// Typically OnExit cleans everything up before we get here, *unless* we cancel
|
// Typically OnExit cleans everything up before we get here, *unless* we cancel
|
||||||
// out of program startup in OnInit (return false) -- then remaining cleanup needs
|
// out of program startup in OnInit (return false) -- then remaining cleanup needs
|
||||||
// to happen here in the destructor.
|
// to happen here in the destructor.
|
||||||
|
@ -485,6 +553,6 @@ struct CrtDebugBreak
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//CrtDebugBreak breakAt( 4327 );
|
//CrtDebugBreak breakAt( 1175 );
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -53,7 +53,7 @@ ConfigOverrides OverrideOptions;
|
||||||
|
|
||||||
static bool HandlePluginError( Exception::PluginError& ex )
|
static bool HandlePluginError( Exception::PluginError& ex )
|
||||||
{
|
{
|
||||||
if( pxDialogExists( DialogId_CoreSettings ) ) return true;
|
if( pxDialogExists( L"CoreSettings" ) ) return true;
|
||||||
|
|
||||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||||
_("\n\nPress Ok to go to the Plugin Configuration Panel.")
|
_("\n\nPress Ok to go to the Plugin Configuration Panel.")
|
||||||
|
@ -64,7 +64,7 @@ static bool HandlePluginError( Exception::PluginError& ex )
|
||||||
g_Conf->SettingsTabName = L"Plugins";
|
g_Conf->SettingsTabName = L"Plugins";
|
||||||
|
|
||||||
// fixme: Send a message to the panel to select the failed plugin.
|
// fixme: Send a message to the panel to select the failed plugin.
|
||||||
if( Dialogs::ConfigurationDialog().ShowModal() == wxID_CANCEL )
|
if( wxGetApp().IssueModalDialog( Dialogs::ConfigurationDialog::GetNameStatic() ) == wxID_CANCEL )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -101,18 +101,6 @@ void Pcsx2App::PostPadKey( wxKeyEvent& evt )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Pcsx2App::ThreadedModalDialog( DialogIdentifiers dialogId )
|
|
||||||
{
|
|
||||||
AffinityAssert_AllowFromMain();
|
|
||||||
|
|
||||||
MsgboxEventResult result;
|
|
||||||
wxCommandEvent joe( pxEVT_OpenModalDialog, dialogId );
|
|
||||||
joe.SetClientData( &result );
|
|
||||||
AddPendingEvent( joe );
|
|
||||||
result.WaitForMe.WaitNoCancel();
|
|
||||||
return result.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Pcsx2App Event Handlers
|
// Pcsx2App Event Handlers
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -130,54 +118,69 @@ void Pcsx2App::OnCoreThreadStatus( wxCommandEvent& evt )
|
||||||
|
|
||||||
void Pcsx2App::OnOpenModalDialog( wxCommandEvent& evt )
|
void Pcsx2App::OnOpenModalDialog( wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
using namespace Dialogs;
|
pxAssertDev( !evt.GetString().IsEmpty(), wxNullChar );
|
||||||
|
|
||||||
MsgboxEventResult& evtres( *((MsgboxEventResult*)evt.GetClientData()) );
|
MsgboxEventResult* evtres = (MsgboxEventResult*)evt.GetClientData();
|
||||||
switch( evt.GetId() )
|
|
||||||
|
wxWindowID result = IssueModalDialog( evt.GetString() );
|
||||||
|
|
||||||
|
if( evtres != NULL )
|
||||||
{
|
{
|
||||||
case DialogId_CoreSettings:
|
evtres->result = result;
|
||||||
{
|
evtres->WaitForMe.Post();
|
||||||
static int _guard = 0;
|
|
||||||
RecursionGuard guard( _guard );
|
|
||||||
if( guard.IsReentrant() ) return;
|
|
||||||
evtres.result = ConfigurationDialog().ShowModal();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DialogId_BiosSelector:
|
|
||||||
{
|
|
||||||
static int _guard = 0;
|
|
||||||
RecursionGuard guard( _guard );
|
|
||||||
if( guard.IsReentrant() ) return;
|
|
||||||
evtres.result = BiosSelectorDialog().ShowModal();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DialogId_LogOptions:
|
|
||||||
{
|
|
||||||
static int _guard = 0;
|
|
||||||
RecursionGuard guard( _guard );
|
|
||||||
if( guard.IsReentrant() ) return;
|
|
||||||
evtres.result = LogOptionsDialog().ShowModal();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DialogId_About:
|
|
||||||
{
|
|
||||||
static int _guard = 0;
|
|
||||||
RecursionGuard guard( _guard );
|
|
||||||
if( guard.IsReentrant() ) return;
|
|
||||||
evtres.result = AboutBoxDialog().ShowModal();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
evtres.WaitForMe.Post();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt )
|
int Pcsx2App::IssueModalDialog( const wxString& dlgName )
|
||||||
{
|
{
|
||||||
Msgbox::OnEvent( evt );
|
if( dlgName.IsEmpty() ) return wxID_CANCEL;
|
||||||
|
|
||||||
|
if( !wxThread::IsMain() )
|
||||||
|
{
|
||||||
|
MsgboxEventResult result;
|
||||||
|
wxCommandEvent joe( pxEVT_OpenModalDialog );
|
||||||
|
joe.SetString( dlgName );
|
||||||
|
joe.SetClientData( &result );
|
||||||
|
AddPendingEvent( joe );
|
||||||
|
result.WaitForMe.WaitNoCancel();
|
||||||
|
return result.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( wxWindow* window = wxFindWindowByName( dlgName ) )
|
||||||
|
{
|
||||||
|
if( wxIsKindOf( window, wxDialog ) )
|
||||||
|
{
|
||||||
|
wxDialog* dialog = (wxDialog*)window;
|
||||||
|
|
||||||
|
window->SetFocus();
|
||||||
|
|
||||||
|
// It's legal to call ShowModal on a non-modal dialog, therefore making
|
||||||
|
// it modal in nature for the needs of whatever other thread of action wants
|
||||||
|
// to block against it:
|
||||||
|
|
||||||
|
if( !dialog->IsModal() )
|
||||||
|
{
|
||||||
|
int result = dialog->ShowModal();
|
||||||
|
dialog->Destroy();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using namespace Dialogs;
|
||||||
|
|
||||||
|
if( dlgName == ConfigurationDialog::GetNameStatic() )
|
||||||
|
return ConfigurationDialog().ShowModal();
|
||||||
|
if( dlgName == BiosSelectorDialog::GetNameStatic() )
|
||||||
|
return BiosSelectorDialog().ShowModal();
|
||||||
|
if( dlgName == LogOptionsDialog::GetNameStatic() )
|
||||||
|
return LogOptionsDialog().ShowModal();
|
||||||
|
if( dlgName == AboutBoxDialog::GetNameStatic() )
|
||||||
|
return AboutBoxDialog().ShowModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return wxID_CANCEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTools::HashMap<int, const GlobalCommandDescriptor*> GlobalAccels( 0, 0xffffffff );
|
HashTools::HashMap<int, const GlobalCommandDescriptor*> GlobalAccels( 0, 0xffffffff );
|
||||||
|
@ -227,15 +230,14 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch( Exception::BiosLoadFailed& ex )
|
catch( Exception::BiosLoadFailed& ex )
|
||||||
{
|
{
|
||||||
bool result = Dialogs::ExtensibleConfirmation( NULL, ConfButtons().OK().Cancel(),
|
wxDialogWithHelpers dialog( NULL, _("PS2 BIOS Error"), wxVERTICAL );
|
||||||
L"PS2 BIOS Error",
|
dialog += dialog.Heading( ex.FormatDisplayMessage() + BIOS_GetMsg_Required() + _("\nPress Ok to go to the BIOS Configuration Panel.") );
|
||||||
ex.FormatDisplayMessage() + BIOS_GetMsg_Required() + _("\nPress Ok to go to the BIOS Configuration Panel.")
|
dialog += new ModalButtonPanel( &dialog, MsgButtons().OKCancel() );
|
||||||
).ShowModal() != wxID_CANCEL;
|
|
||||||
|
if( dialog.ShowModal() == wxID_CANCEL )
|
||||||
if( !result )
|
|
||||||
Console.Warning( "User denied option to re-configure BIOS." );
|
Console.Warning( "User denied option to re-configure BIOS." );
|
||||||
|
|
||||||
if( Dialogs::BiosSelectorDialog().ShowModal() != wxID_CANCEL )
|
if( IssueModalDialog( Dialogs::BiosSelectorDialog::GetNameStatic() ) != wxID_CANCEL )
|
||||||
{
|
{
|
||||||
SysExecute();
|
SysExecute();
|
||||||
}
|
}
|
||||||
|
@ -268,15 +270,22 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
catch( Exception::ThreadTimedOut& ex )
|
catch( Exception::ThreadTimedOut& ex )
|
||||||
{
|
{
|
||||||
|
// [TODO] Bind a listener to the CoreThread status, and automatically close the dialog
|
||||||
|
// if the thread starts responding while we're waiting (not hard in fact, but I'm getting
|
||||||
|
// a little tired, so maybe later!) --air
|
||||||
|
|
||||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||||
int result = Dialogs::ExtensibleConfirmation( NULL, ConfButtons().Ignore().Cancel().Custom( _("Terminate") ),
|
wxDialogWithHelpers dialog( NULL, _("PCSX2 Unresponsive Thread"), wxVERTICAL );
|
||||||
_("PCSX2 Unresponsive Thread"), ex.FormatDisplayMessage() + L"\n\n" +
|
|
||||||
|
dialog += dialog.Heading( ex.FormatDisplayMessage() + L"\n\n" +
|
||||||
pxE( ".Popup Error:Thread Deadlock Actions",
|
pxE( ".Popup Error:Thread Deadlock Actions",
|
||||||
L"'Ignore' to continue waiting for the thread to respond.\n"
|
L"'Ignore' to continue waiting for the thread to respond.\n"
|
||||||
L"'Cancel' to attempt to cancel the thread.\n"
|
L"'Cancel' to attempt to cancel the thread.\n"
|
||||||
L"'Terminate' to quit PCSX2 immediately.\n"
|
L"'Terminate' to quit PCSX2 immediately.\n"
|
||||||
)
|
)
|
||||||
).ShowModal();
|
);
|
||||||
|
|
||||||
|
int result = pxIssueConfirmation( dialog, MsgButtons().Ignore().Cancel().Custom( _("Terminate") ) );
|
||||||
|
|
||||||
if( result == pxID_CUSTOM )
|
if( result == pxID_CUSTOM )
|
||||||
{
|
{
|
||||||
|
@ -386,14 +395,14 @@ int Pcsx2App::OnExit()
|
||||||
// is a matter of programmer preference).
|
// is a matter of programmer preference).
|
||||||
MainEmuFrame& Pcsx2App::GetMainFrame() const
|
MainEmuFrame& Pcsx2App::GetMainFrame() const
|
||||||
{
|
{
|
||||||
pxAssert( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
pxAssume( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
||||||
pxAssert( m_MainFrame != NULL );
|
pxAssume( m_MainFrame != NULL );
|
||||||
return *m_MainFrame;
|
return *m_MainFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSFrame& Pcsx2App::GetGSFrame() const
|
GSFrame& Pcsx2App::GetGSFrame() const
|
||||||
{
|
{
|
||||||
pxAssert( m_gsFrame != NULL );
|
pxAssume( m_gsFrame != NULL );
|
||||||
return *m_gsFrame;
|
return *m_gsFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,6 +603,8 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
|
||||||
// Full system reset stops the core thread and unloads all core plugins *completely*.
|
// Full system reset stops the core thread and unloads all core plugins *completely*.
|
||||||
void Pcsx2App::SysReset()
|
void Pcsx2App::SysReset()
|
||||||
{
|
{
|
||||||
|
StateCopy_Clear();
|
||||||
|
|
||||||
CoreThread.Reset();
|
CoreThread.Reset();
|
||||||
CoreThread.ReleaseResumeLock();
|
CoreThread.ReleaseResumeLock();
|
||||||
m_CorePlugins = NULL;
|
m_CorePlugins = NULL;
|
||||||
|
|
|
@ -176,8 +176,15 @@ ConsoleLogFrame::ColorArray::~ColorArray()
|
||||||
|
|
||||||
void ConsoleLogFrame::ColorArray::Create( int fontsize )
|
void ConsoleLogFrame::ColorArray::Create( int fontsize )
|
||||||
{
|
{
|
||||||
const wxFont fixed( fontsize, wxMODERN, wxNORMAL, wxNORMAL );
|
// pxGetFixedFont selects Andale Mono on Win32, which is nice visually but
|
||||||
const wxFont fixedB( fontsize, wxMODERN, wxNORMAL, wxBOLD );
|
// unfortunately has inconsistently spaced bold versions, so it's not good
|
||||||
|
// for our console.
|
||||||
|
|
||||||
|
const wxFont fixed( pxGetFixedFont( fontsize ) );
|
||||||
|
const wxFont fixedB( pxGetFixedFont( fontsize+1, wxBOLD ) );
|
||||||
|
|
||||||
|
//const wxFont fixed( fontsize, wxMODERN, wxNORMAL, wxNORMAL );
|
||||||
|
//const wxFont fixedB( fontsize, wxMODERN, wxNORMAL, wxBOLD );
|
||||||
|
|
||||||
// Standard R, G, B format:
|
// Standard R, G, B format:
|
||||||
new (&m_table[Color_Default]) wxTextAttr( wxColor( 0, 0, 0 ), wxNullColour, fixed );
|
new (&m_table[Color_Default]) wxTextAttr( wxColor( 0, 0, 0 ), wxNullColour, fixed );
|
||||||
|
@ -262,6 +269,10 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A
|
||||||
m_TextCtrl.SetBackgroundColour( wxColor( 230, 235, 242 ) );
|
m_TextCtrl.SetBackgroundColour( wxColor( 230, 235, 242 ) );
|
||||||
m_TextCtrl.SetDefaultStyle( m_ColorTable[DefaultConsoleColor] );
|
m_TextCtrl.SetDefaultStyle( m_ColorTable[DefaultConsoleColor] );
|
||||||
|
|
||||||
|
// SetDefaultStyle only sets the style of text in the control. We need to
|
||||||
|
// also set the font of the control, so that sizing logic knows what font we use:
|
||||||
|
m_TextCtrl.SetFont( m_ColorTable[DefaultConsoleColor].GetFont() );
|
||||||
|
|
||||||
wxMenu& menuLog (*new wxMenu());
|
wxMenu& menuLog (*new wxMenu());
|
||||||
wxMenu& menuAppear (*new wxMenu());
|
wxMenu& menuAppear (*new wxMenu());
|
||||||
wxMenu& menuSources (*new wxMenu());
|
wxMenu& menuSources (*new wxMenu());
|
||||||
|
|
|
@ -96,10 +96,10 @@ protected:
|
||||||
EventListenerBinding<PluginEventType> m_Listener_CorePluginStatus;
|
EventListenerBinding<PluginEventType> m_Listener_CorePluginStatus;
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
int m_win32_StupidRefreshTricks;
|
|
||||||
int m_win32_LinesPerPage;
|
int m_win32_LinesPerPage;
|
||||||
int m_win32_LinesPerScroll;
|
int m_win32_LinesPerScroll;
|
||||||
#endif
|
#endif
|
||||||
|
bool m_IsPaused;
|
||||||
bool m_FreezeWrites;
|
bool m_FreezeWrites;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include <wx/mstream.h>
|
#include <wx/mstream.h>
|
||||||
#include <wx/hyperlink.h>
|
#include <wx/hyperlink.h>
|
||||||
|
|
||||||
|
using namespace pxSizerFlags;
|
||||||
|
|
||||||
namespace Dialogs
|
namespace Dialogs
|
||||||
{
|
{
|
||||||
// Helper class for creating wxStaticText labels which are aligned to center.
|
// Helper class for creating wxStaticText labels which are aligned to center.
|
||||||
|
@ -45,11 +47,14 @@ namespace Dialogs
|
||||||
// AboutBoxDialog Implementation
|
// AboutBoxDialog Implementation
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent )
|
||||||
wxDialogWithHelpers( parent, id, _("About PCSX2"), false ),
|
: wxDialogWithHelpers( parent, _("About PCSX2"), wxVERTICAL )
|
||||||
m_bitmap_dualshock( this, wxID_ANY, wxBitmap( EmbeddedImage<res_Dualshock>().Get() ),
|
, m_bitmap_dualshock( this, wxID_ANY, wxBitmap( EmbeddedImage<res_Dualshock>().Get() ),
|
||||||
wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN )
|
wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
SetName( GetNameStatic() );
|
||||||
|
|
||||||
static const wxString LabelAuthors = fromUTF8(
|
static const wxString LabelAuthors = fromUTF8(
|
||||||
"Developers"
|
"Developers"
|
||||||
"\n\n"
|
"\n\n"
|
||||||
|
@ -80,10 +85,6 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
||||||
"F|RES, MrBrown, razorblade, Seta-san, Skarmeth, feal87"
|
"F|RES, MrBrown, razorblade, Seta-san, Skarmeth, feal87"
|
||||||
);
|
);
|
||||||
|
|
||||||
SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
|
||||||
|
|
||||||
*this += Text(_("PCSX2 - Playstation 2 Emulator"));
|
|
||||||
|
|
||||||
// This sizer holds text of the authors and a logo!
|
// This sizer holds text of the authors and a logo!
|
||||||
wxBoxSizer& AuthLogoSizer = *new wxBoxSizer( wxHORIZONTAL );
|
wxBoxSizer& AuthLogoSizer = *new wxBoxSizer( wxHORIZONTAL );
|
||||||
|
|
||||||
|
@ -99,18 +100,21 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
||||||
label_auth->Wrap( 340 );
|
label_auth->Wrap( 340 );
|
||||||
label_greets->Wrap( 200 );
|
label_greets->Wrap( 200 );
|
||||||
|
|
||||||
aboutUs.Add( label_auth, pxSizerFlags::StdExpand() );
|
aboutUs += label_auth | StdExpand();
|
||||||
contribs.Add( label_greets, pxSizerFlags::StdExpand() );
|
contribs += label_greets | StdExpand();
|
||||||
|
|
||||||
AuthLogoSizer.Add( &aboutUs );
|
AuthLogoSizer += aboutUs;
|
||||||
AuthLogoSizer.AddSpacer( 7 );
|
AuthLogoSizer += 7;
|
||||||
AuthLogoSizer.Add( &contribs );
|
AuthLogoSizer += contribs;
|
||||||
|
|
||||||
ContribSizer.AddStretchSpacer( 1 );
|
ContribSizer.AddStretchSpacer( 1 );
|
||||||
ContribSizer.Add( &m_bitmap_dualshock, pxSizerFlags::StdSpace() );
|
ContribSizer += m_bitmap_dualshock | StdSpace();
|
||||||
ContribSizer.AddStretchSpacer( 1 );
|
ContribSizer.AddStretchSpacer( 1 );
|
||||||
|
|
||||||
*this += AuthLogoSizer | pxSizerFlags::StdSpace();
|
// Main (top-level) layout
|
||||||
|
|
||||||
|
*this += Text(_("PCSX2 - Playstation 2 Emulator"));
|
||||||
|
*this += AuthLogoSizer | StdSpace();
|
||||||
|
|
||||||
*this += new wxHyperlinkCtrl( this, wxID_ANY,
|
*this += new wxHyperlinkCtrl( this, wxID_ANY,
|
||||||
_("Pcsx2 Official Website and Forums"), L"http://www.pcsx2.net"
|
_("Pcsx2 Official Website and Forums"), L"http://www.pcsx2.net"
|
||||||
|
@ -120,10 +124,6 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
||||||
_("Pcsx2 Official Svn Repository at Googlecode"), L"http://code.google.com/p/pcsx2"
|
_("Pcsx2 Official Svn Repository at Googlecode"), L"http://code.google.com/p/pcsx2"
|
||||||
) | wxSizerFlags(1).Center().Border( wxALL, 3 );
|
) | wxSizerFlags(1).Center().Border( wxALL, 3 );
|
||||||
|
|
||||||
*this += ContribSizer | pxSizerFlags::StdExpand();
|
*this += ContribSizer | StdExpand();
|
||||||
|
*this += new wxButton( this, wxID_OK, L"I've seen enough") | StdCenter();
|
||||||
*this += new wxButton( this, wxID_OK, L"I've seen enough") | pxSizerFlags::StdCenter();
|
|
||||||
|
|
||||||
Fit();
|
|
||||||
CenterOnScreen();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* 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 "App.h"
|
||||||
|
#include "Dialogs/ModalPopups.h"
|
||||||
|
|
||||||
|
using namespace pxSizerFlags;
|
||||||
|
|
||||||
|
Dialogs::AssertionDialog::AssertionDialog( const wxString& text, const wxString& stacktrace )
|
||||||
|
: wxDialogWithHelpers( NULL, _("PCSX2 Assertion Failure"), false, !stacktrace.IsEmpty() )
|
||||||
|
{
|
||||||
|
m_idealWidth = 720;
|
||||||
|
|
||||||
|
wxFlexGridSizer* flexgrid = new wxFlexGridSizer( 1 );
|
||||||
|
flexgrid->AddGrowableCol( 0 );
|
||||||
|
SetSizer( flexgrid );
|
||||||
|
|
||||||
|
wxTextCtrl* traceArea = NULL;
|
||||||
|
|
||||||
|
if( !stacktrace.IsEmpty() )
|
||||||
|
{
|
||||||
|
flexgrid->AddGrowableRow( 1 );
|
||||||
|
|
||||||
|
traceArea = new wxTextCtrl(
|
||||||
|
this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||||
|
wxTE_READONLY | wxTE_MULTILINE | wxTE_RICH2 | wxHSCROLL
|
||||||
|
);
|
||||||
|
|
||||||
|
traceArea->SetDefaultStyle( wxTextAttr( wxNullColour, wxNullColour, pxGetFixedFont() ) );
|
||||||
|
traceArea->SetFont( pxGetFixedFont() );
|
||||||
|
|
||||||
|
int fonty;
|
||||||
|
traceArea->GetTextExtent( L"blaH yeah", NULL, &fonty );
|
||||||
|
|
||||||
|
traceArea->WriteText( stacktrace );
|
||||||
|
traceArea->SetMinSize( wxSize( GetIdealWidth()-24, (fonty+1)*18 ) );
|
||||||
|
traceArea->ShowPosition(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
*this += Heading( text );
|
||||||
|
|
||||||
|
if( traceArea != NULL ) *this += traceArea | pxExpand.Border(wxTOP|wxLEFT|wxRIGHT,8);
|
||||||
|
|
||||||
|
*this += Heading(
|
||||||
|
L"\nDo you want to stop the program [Yes/No]?"
|
||||||
|
L"\nOr press [Ignore] to suppress further assertions."
|
||||||
|
);
|
||||||
|
|
||||||
|
*this += new ModalButtonPanel( this, MsgButtons().YesNo().Ignore() ) | StdCenter();
|
||||||
|
|
||||||
|
if( wxWindow* idyes = FindWindowById( wxID_YES ) )
|
||||||
|
idyes->SetFocus();
|
||||||
|
}
|
||||||
|
|
|
@ -55,10 +55,12 @@ void Dialogs::ConfigurationDialog::AddPage( const char* label, int iconid )
|
||||||
( labelstr == g_Conf->SettingsTabName ), iconid );
|
( labelstr == g_Conf->SettingsTabName ), iconid );
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id )
|
Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent )
|
||||||
: wxDialogWithHelpers( parent, id, _("PCSX2 Configuration"), true )
|
: wxDialogWithHelpers( parent, _("PCSX2 Configuration"), true )
|
||||||
, m_listbook( *new wxListbook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, s_orient ) )
|
, m_listbook( *new wxListbook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, s_orient ) )
|
||||||
{
|
{
|
||||||
|
SetName( GetNameStatic() );
|
||||||
|
|
||||||
m_idealWidth = 600;
|
m_idealWidth = 600;
|
||||||
|
|
||||||
m_listbook.SetImageList( &wxGetApp().GetImgList_Config() );
|
m_listbook.SetImageList( &wxGetApp().GetImgList_Config() );
|
||||||
|
@ -85,9 +87,6 @@ Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id )
|
||||||
|
|
||||||
FindWindow( wxID_APPLY )->Disable();
|
FindWindow( wxID_APPLY )->Disable();
|
||||||
|
|
||||||
Fit();
|
|
||||||
CenterOnScreen();
|
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
// Depending on Windows version and user appearance settings, the default icon spacing can be
|
// Depending on Windows version and user appearance settings, the default icon spacing can be
|
||||||
// way over generous. This little bit of Win32-specific code ensures proper icon spacing, scaled
|
// way over generous. This little bit of Win32-specific code ensures proper icon spacing, scaled
|
||||||
|
@ -103,6 +102,8 @@ Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id )
|
||||||
Connect( wxID_APPLY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnApply_Click ) );
|
Connect( wxID_APPLY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnApply_Click ) );
|
||||||
Connect( wxID_SAVE, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnScreenshot_Click ) );
|
Connect( wxID_SAVE, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnScreenshot_Click ) );
|
||||||
|
|
||||||
|
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler(ConfigurationDialog::OnCloseWindow) );
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Bind a variety of standard "something probably changed" events. If the user invokes
|
// Bind a variety of standard "something probably changed" events. If the user invokes
|
||||||
// any of these, we'll automatically de-gray the Apply button for this dialog box. :)
|
// any of these, we'll automatically de-gray the Apply button for this dialog box. :)
|
||||||
|
@ -126,6 +127,12 @@ Dialogs::ConfigurationDialog::~ConfigurationDialog() throw()
|
||||||
g_ApplyState.DoCleanup();
|
g_ApplyState.DoCleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Dialogs::ConfigurationDialog::OnCloseWindow( wxCloseEvent& evt )
|
||||||
|
{
|
||||||
|
if( !IsModal() ) Destroy();
|
||||||
|
evt.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
void Dialogs::ConfigurationDialog::OnOk_Click( wxCommandEvent& evt )
|
void Dialogs::ConfigurationDialog::OnOk_Click( wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
if( g_ApplyState.ApplyAll() )
|
if( g_ApplyState.ApplyAll() )
|
||||||
|
@ -133,8 +140,6 @@ void Dialogs::ConfigurationDialog::OnOk_Click( wxCommandEvent& evt )
|
||||||
FindWindow( wxID_APPLY )->Disable();
|
FindWindow( wxID_APPLY )->Disable();
|
||||||
g_Conf->SettingsTabName = m_labels[m_listbook.GetSelection()];
|
g_Conf->SettingsTabName = m_labels[m_listbook.GetSelection()];
|
||||||
AppSaveSettings();
|
AppSaveSettings();
|
||||||
|
|
||||||
Close();
|
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,9 +186,11 @@ void Dialogs::ConfigurationDialog::OnScreenshot_Click( wxCommandEvent& evt )
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
Dialogs::BiosSelectorDialog::BiosSelectorDialog( wxWindow* parent, int id )
|
Dialogs::BiosSelectorDialog::BiosSelectorDialog( wxWindow* parent )
|
||||||
: wxDialogWithHelpers( parent, id, _("BIOS Selector"), false )
|
: wxDialogWithHelpers( parent, _("BIOS Selector"), false )
|
||||||
{
|
{
|
||||||
|
SetName( GetNameStatic() );
|
||||||
|
|
||||||
m_idealWidth = 500;
|
m_idealWidth = 500;
|
||||||
|
|
||||||
wxBoxSizer& bleh( *new wxBoxSizer( wxVERTICAL ) );
|
wxBoxSizer& bleh( *new wxBoxSizer( wxVERTICAL ) );
|
||||||
|
|
|
@ -33,7 +33,9 @@ namespace Dialogs
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ConfigurationDialog() throw();
|
virtual ~ConfigurationDialog() throw();
|
||||||
ConfigurationDialog(wxWindow* parent=NULL, int id=DialogId_CoreSettings);
|
ConfigurationDialog(wxWindow* parent=NULL);
|
||||||
|
|
||||||
|
static const wxChar* GetNameStatic() { return L"Dialog:CoreSettings"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template< typename T >
|
template< typename T >
|
||||||
|
@ -43,6 +45,8 @@ namespace Dialogs
|
||||||
void OnCancel_Click( wxCommandEvent& evt );
|
void OnCancel_Click( wxCommandEvent& evt );
|
||||||
void OnApply_Click( wxCommandEvent& evt );
|
void OnApply_Click( wxCommandEvent& evt );
|
||||||
void OnScreenshot_Click( wxCommandEvent& evt );
|
void OnScreenshot_Click( wxCommandEvent& evt );
|
||||||
|
|
||||||
|
void OnCloseWindow( wxCloseEvent& evt );
|
||||||
|
|
||||||
virtual void OnSomethingChanged( wxCommandEvent& evt )
|
virtual void OnSomethingChanged( wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
|
@ -54,14 +58,15 @@ namespace Dialogs
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class BiosSelectorDialog : public wxDialogWithHelpers
|
class BiosSelectorDialog : public wxDialogWithHelpers
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~BiosSelectorDialog() throw() {}
|
virtual ~BiosSelectorDialog() throw() {}
|
||||||
BiosSelectorDialog( wxWindow* parent=NULL, int id=DialogId_BiosSelector );
|
BiosSelectorDialog( wxWindow* parent=NULL );
|
||||||
|
|
||||||
|
static const wxChar* GetNameStatic() { return L"Dialog:BiosSelector"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnOk_Click( wxCommandEvent& evt );
|
void OnOk_Click( wxCommandEvent& evt );
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
#include "ModalPopups.h"
|
#include "ModalPopups.h"
|
||||||
#include "Utilities/StringHelpers.h"
|
#include "Utilities/StringHelpers.h"
|
||||||
|
|
||||||
bool ConfButtons::Allows( wxWindowID id ) const
|
using namespace pxSizerFlags;
|
||||||
|
|
||||||
|
bool MsgButtons::Allows( wxWindowID id ) const
|
||||||
{
|
{
|
||||||
switch( id )
|
switch( id )
|
||||||
{
|
{
|
||||||
|
@ -63,7 +65,7 @@ static wxString ResultToString( int result )
|
||||||
return wxEmptyString;
|
return wxEmptyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
static wxWindowID ParseThatResult( const wxString& src, const ConfButtons& validTypes )
|
static wxWindowID ParseThatResult( const wxString& src, const MsgButtons& validTypes )
|
||||||
{
|
{
|
||||||
if( !pxAssert( !src.IsEmpty() ) ) return wxID_ANY;
|
if( !pxAssert( !src.IsEmpty() ) ) return wxID_ANY;
|
||||||
|
|
||||||
|
@ -85,7 +87,53 @@ static wxWindowID ParseThatResult( const wxString& src, const ConfButtons& valid
|
||||||
return wxID_ANY;
|
return wxID_ANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxWindowID Dialogs::IssueConfirmation( ExtensibleConfirmation& confirmDlg, const wxString& disablerKey )
|
static bool pxTrySetFocus( wxWindow& parent, wxWindowID id )
|
||||||
|
{
|
||||||
|
if( wxWindow* found = parent.FindWindowById( id ) )
|
||||||
|
{
|
||||||
|
found->SetFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pxTrySetFocus( wxWindow* parent, wxWindowID id )
|
||||||
|
{
|
||||||
|
if( parent == NULL ) return false;
|
||||||
|
pxTrySetFocus( *parent, id );
|
||||||
|
}
|
||||||
|
|
||||||
|
void MsgButtons::SetBestFocus( wxWindow& dialog ) const
|
||||||
|
{
|
||||||
|
if( HasOK() && pxTrySetFocus( dialog, wxID_OK ) ) return;
|
||||||
|
if( HasNo() && pxTrySetFocus( dialog, wxID_NO ) ) return;
|
||||||
|
if( HasClose() && pxTrySetFocus( dialog, wxID_CLOSE ) ) return;
|
||||||
|
if( HasRetry() && pxTrySetFocus( dialog, wxID_RETRY ) ) return;
|
||||||
|
|
||||||
|
// Other confirmational types of buttons must be explicitly focused by the user or
|
||||||
|
// by an implementing dialog. We won't do it here implicitly because accidental
|
||||||
|
// "on focus" typed keys could invoke really unwanted actions.
|
||||||
|
|
||||||
|
// (typically close/ok/retry/etc. aren't so bad that accidental clicking does terrible things)
|
||||||
|
}
|
||||||
|
|
||||||
|
void MsgButtons::SetBestFocus( wxWindow* dialog ) const
|
||||||
|
{
|
||||||
|
if( dialog == NULL ) return;
|
||||||
|
SetBestFocus( *dialog );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxWindowID pxIssueConfirmation( wxDialogWithHelpers& confirmDlg, const MsgButtons& buttons )
|
||||||
|
{
|
||||||
|
confirmDlg += new ModalButtonPanel( &confirmDlg, buttons ) | pxCenter.Border( wxTOP, 8 );
|
||||||
|
buttons.SetBestFocus( confirmDlg );
|
||||||
|
return confirmDlg.ShowModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxWindowID pxIssueConfirmation( wxDialogWithHelpers& confirmDlg, const MsgButtons& buttons, const wxString& disablerKey )
|
||||||
{
|
{
|
||||||
wxConfigBase* cfg = GetAppConfig();
|
wxConfigBase* cfg = GetAppConfig();
|
||||||
|
|
||||||
|
@ -112,135 +160,143 @@ wxWindowID Dialogs::IssueConfirmation( ExtensibleConfirmation& confirmDlg, const
|
||||||
result = split[0];
|
result = split[0];
|
||||||
if( result == L"disabled" || result == L"off" || result == L"no" )
|
if( result == L"disabled" || result == L"off" || result == L"no" )
|
||||||
{
|
{
|
||||||
int result = ParseThatResult( split[1], confirmDlg.GetButtons() );
|
int result = ParseThatResult( split[1], buttons );
|
||||||
if( result != wxID_ANY ) return result;
|
if( result != wxID_ANY ) return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cfg == NULL ) return confirmDlg.ShowModal();
|
pxCheckBox* DisablerCtrl = NULL;
|
||||||
|
if( cfg != NULL )
|
||||||
// Add an option that allows the user to disable this popup from showing again.
|
|
||||||
// (and if the config hasn't been initialized yet, then assume the dialog as non-disablable)
|
|
||||||
|
|
||||||
pxCheckBox& DisablerCtrl( *new pxCheckBox(&confirmDlg, _("Do not show this dialog again.")) );
|
|
||||||
confirmDlg.GetExtensibleSizer().Add( &DisablerCtrl, wxSizerFlags().Centre() );
|
|
||||||
|
|
||||||
if( confirmDlg.GetButtons() != ConfButtons().OK() )
|
|
||||||
pxSetToolTip(&DisablerCtrl, _("Disables this popup and whatever response you select here will be automatically used from now on."));
|
|
||||||
else
|
|
||||||
pxSetToolTip(&DisablerCtrl, _("The popup will not be shown again. This setting can be undone from the settings panels."));
|
|
||||||
|
|
||||||
confirmDlg.Fit();
|
|
||||||
|
|
||||||
int modalResult = confirmDlg.ShowModal();
|
|
||||||
|
|
||||||
wxString cfgResult = ResultToString( modalResult );
|
|
||||||
if( DisablerCtrl.IsChecked() && !cfgResult.IsEmpty() )
|
|
||||||
{
|
{
|
||||||
cfg->SetPath( L"/PopupDisablers" );
|
// Add an option that allows the user to disable this popup from showing again.
|
||||||
cfg->Write( disablerKey, L"disabled," + cfgResult );
|
// (and if the config hasn't been initialized yet, then assume the dialog as non-disablable)
|
||||||
cfg->SetPath( L"/" );
|
|
||||||
|
DisablerCtrl = new pxCheckBox(&confirmDlg, _("Do not show this dialog again."));
|
||||||
|
|
||||||
|
confirmDlg += 8;
|
||||||
|
confirmDlg += DisablerCtrl | wxSF.Centre();
|
||||||
|
|
||||||
|
if( buttons != MsgButtons().OK() )
|
||||||
|
pxSetToolTip(DisablerCtrl, _("Disables this popup and whatever response you select here will be automatically used from now on."));
|
||||||
|
else
|
||||||
|
pxSetToolTip(DisablerCtrl, _("The popup will not be shown again. This setting can be undone from the settings panels."));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int modalResult = pxIssueConfirmation( confirmDlg, buttons );
|
||||||
|
|
||||||
|
if( cfg != NULL )
|
||||||
|
{
|
||||||
|
wxString cfgResult = ResultToString( modalResult );
|
||||||
|
if( DisablerCtrl->IsChecked() && !cfgResult.IsEmpty() )
|
||||||
|
{
|
||||||
|
cfg->SetPath( L"/PopupDisablers" );
|
||||||
|
cfg->Write( disablerKey, L"disabled," + cfgResult );
|
||||||
|
cfg->SetPath( L"/" );
|
||||||
|
cfg->Flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return modalResult;
|
return modalResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialogs::ExtensibleConfirmation::ExtensibleConfirmation( wxWindow* parent, const ConfButtons& type, const wxString& title, const wxString& msg )
|
ModalButtonPanel::ModalButtonPanel( wxWindow* parent, const MsgButtons& buttons )
|
||||||
: wxDialogWithHelpers( parent, wxID_ANY, title, false )
|
: wxPanelWithHelpers( parent, wxHORIZONTAL )
|
||||||
, m_ExtensibleSizer( *new wxBoxSizer( wxVERTICAL ) )
|
|
||||||
, m_ButtonSizer( *new wxBoxSizer( wxHORIZONTAL ) )
|
|
||||||
{
|
{
|
||||||
m_Buttons = type;
|
|
||||||
m_idealWidth = 500;
|
|
||||||
|
|
||||||
SetSizer( new wxBoxSizer(wxVERTICAL) );
|
|
||||||
|
|
||||||
// Populate the Button Sizer.
|
// Populate the Button Sizer.
|
||||||
// We prefer this over the built-in wxWidgets ButtonSizer stuff used for other types of
|
// We prefer this over the built-in wxWidgets ButtonSizer stuff used for other types of
|
||||||
// dialogs because we offer more button types, and we don't want the MSW default behavior
|
// dialogs because we offer more button types, and we don't want the MSW default behavior
|
||||||
// of right-justified buttons.
|
// of right-justified buttons.
|
||||||
|
|
||||||
if( type.HasCustom() )
|
if( buttons.HasCustom() )
|
||||||
AddCustomButton( pxID_CUSTOM, type.GetCustomLabel() );
|
AddCustomButton( pxID_CUSTOM, buttons.GetCustomLabel() );
|
||||||
|
|
||||||
// Order of wxID_RESET and custom button have been picked fairly arbitrarily, since there's
|
// Order of wxID_RESET and custom button have been picked fairly arbitrarily, since there's
|
||||||
// no standard governing those.
|
// no standard governing those.
|
||||||
|
|
||||||
#ifdef __WXGTK__
|
#ifdef __WXGTK__
|
||||||
// GTK+ / Linux inverts OK/CANCEL order -- cancel / no first, OK / Yes later. >_<
|
// GTK+ / Linux inverts OK/CANCEL order -- cancel / no first, OK / Yes later. >_<
|
||||||
if( type.HasCancel() )
|
if( buttons.HasCancel() )
|
||||||
AddActionButton( wxID_CANCEL );
|
AddActionButton( wxID_CANCEL );
|
||||||
|
|
||||||
if( type.HasNo() )
|
if( buttons.HasNo() )
|
||||||
{
|
{
|
||||||
AddActionButton( wxID_NO );
|
AddActionButton( wxID_NO );
|
||||||
if( type.AllowsToAll() ) AddActionButton( wxID_NOTOALL );
|
if( buttons.AllowsToAll() ) AddActionButton( wxID_NOTOALL );
|
||||||
}
|
}
|
||||||
if( type.HasOK() || type.HasYes() ) // Extra space between Affirm and Cancel Actions
|
|
||||||
m_ButtonSizer.Add(0, 0, 1, wxEXPAND, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( type.HasOK() )
|
if( buttons.HasIgnore() )
|
||||||
|
AddCustomButton( wxID_IGNORE, _("Ignore") );
|
||||||
|
|
||||||
|
if( buttons.HasOK() || buttons.HasYes() ) // Extra space between Affirm and Cancel Actions
|
||||||
|
GetSizer()->Add(0, 0, 1, wxEXPAND, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( buttons.HasOK() )
|
||||||
AddActionButton( wxID_OK );
|
AddActionButton( wxID_OK );
|
||||||
|
|
||||||
if( type.HasYes() )
|
if( buttons.HasYes() )
|
||||||
{
|
{
|
||||||
AddActionButton( wxID_YES );
|
AddActionButton( wxID_YES );
|
||||||
if( type.AllowsToAll() )
|
if( buttons.AllowsToAll() )
|
||||||
AddActionButton( wxID_YESTOALL );
|
AddActionButton( wxID_YESTOALL );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( type.HasReset() )
|
#ifdef __WXGTK__
|
||||||
|
if( buttons.HasRetry() )
|
||||||
|
AddActionButton( wxID_RETRY );
|
||||||
|
|
||||||
|
if( buttons.HasAbort() )
|
||||||
|
AddActionButton( wxID_ABORT );
|
||||||
|
#else
|
||||||
|
if( buttons.HasAbort() )
|
||||||
|
AddActionButton( wxID_ABORT );
|
||||||
|
|
||||||
|
if( buttons.HasRetry() )
|
||||||
|
AddActionButton( wxID_RETRY );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( buttons.HasReset() )
|
||||||
AddCustomButton( wxID_RESET, _("Reset") );
|
AddCustomButton( wxID_RESET, _("Reset") );
|
||||||
|
|
||||||
if( type.HasClose() )
|
if( buttons.HasClose() )
|
||||||
AddActionButton( wxID_CLOSE );
|
AddActionButton( wxID_CLOSE );
|
||||||
|
|
||||||
#ifndef __WXGTK__
|
#ifndef __WXGTK__
|
||||||
if( type.HasNo() || type.HasCancel() ) // Extra space between Affirm and Cancel Actions
|
if( buttons.HasNo() )
|
||||||
m_ButtonSizer.Add(0, 0, 1, wxEXPAND, 0);
|
|
||||||
|
|
||||||
if( type.HasNo() )
|
|
||||||
{
|
{
|
||||||
AddActionButton( wxID_NO );
|
AddActionButton( wxID_NO );
|
||||||
if( type.AllowsToAll() )
|
if( buttons.AllowsToAll() )
|
||||||
AddActionButton( wxID_NOTOALL );
|
AddActionButton( wxID_NOTOALL );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( type.HasCancel() )
|
if( buttons.HasIgnore() )
|
||||||
|
AddCustomButton( wxID_IGNORE, _("Ignore") );
|
||||||
|
|
||||||
|
if( buttons.HasCancel() )
|
||||||
AddActionButton( wxID_CANCEL );
|
AddActionButton( wxID_CANCEL );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --------------------------------
|
|
||||||
// Finalize Sizers and Layout
|
|
||||||
// --------------------------------
|
|
||||||
|
|
||||||
// Add the message padded some (StdCenter gives us a 5 pt padding). Helps emphasize it a bit.
|
|
||||||
wxBoxSizer& msgPadSizer( *new wxBoxSizer(wxVERTICAL) );
|
|
||||||
msgPadSizer += Heading( msg );
|
|
||||||
|
|
||||||
*this += msgPadSizer | pxSizerFlags::StdCenter();
|
|
||||||
*this += m_ExtensibleSizer | pxCentre;
|
|
||||||
*this += m_ButtonSizer | pxSizerFlags::StdCenter();
|
|
||||||
|
|
||||||
Fit();
|
|
||||||
CenterOnScreen();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dialogs::ExtensibleConfirmation::OnActionButtonClicked( wxCommandEvent& evt )
|
void ModalButtonPanel::OnActionButtonClicked( wxCommandEvent& evt )
|
||||||
{
|
{
|
||||||
EndModal( evt.GetId() );
|
evt.Skip();
|
||||||
|
wxWindow* toplevel = wxGetTopLevelParent( this );
|
||||||
|
if( toplevel != NULL && wxIsKindOf(toplevel, wxDialog) )
|
||||||
|
((wxDialog*)toplevel)->EndModal( evt.GetId() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dialogs::ExtensibleConfirmation::AddCustomButton( wxWindowID id, const wxString& label )
|
void ModalButtonPanel::AddCustomButton( wxWindowID id, const wxString& label )
|
||||||
{
|
{
|
||||||
m_ButtonSizer.Add( new wxButton( this, id, label ), pxSizerFlags::StdButton() )->SetProportion( 6 );
|
*this += new wxButton( this, id, label ) | StdButton().Proportion(6);
|
||||||
Connect( id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ExtensibleConfirmation::OnActionButtonClicked ) );
|
Connect( id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModalButtonPanel::OnActionButtonClicked ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dialogs::ExtensibleConfirmation::AddActionButton( wxWindowID id )
|
// This is for buttons that are defined internally by wxWidgets, such as wxID_CANCEL, wxID_ABORT, etc.
|
||||||
|
// wxWidgets will assign the labels and stuff for us. :D
|
||||||
|
void ModalButtonPanel::AddActionButton( wxWindowID id )
|
||||||
{
|
{
|
||||||
m_ButtonSizer.Add( new wxButton( this, id ), pxSizerFlags::StdButton() )->SetProportion( 6 );
|
*this += new wxButton( this, id ) | StdButton().Proportion(6);
|
||||||
Connect( id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ExtensibleConfirmation::OnActionButtonClicked ) );
|
Connect( id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModalButtonPanel::OnActionButtonClicked ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <wx/file.h>
|
#include <wx/file.h>
|
||||||
|
|
||||||
using namespace Panels;
|
using namespace Panels;
|
||||||
|
using namespace pxSizerFlags;
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
static T& MakeWizWidget( int pageid, wxWizardPage* src )
|
static T& MakeWizWidget( int pageid, wxWizardPage* src )
|
||||||
|
@ -48,8 +49,6 @@ Panels::SettingsDirPickerPanel::SettingsDirPickerPanel( wxWindow* parent ) :
|
||||||
), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE
|
), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE
|
||||||
), wxSizerFlags().Expand().Border( wxBOTTOM, 6 )
|
), wxSizerFlags().Expand().Border( wxBOTTOM, 6 )
|
||||||
);
|
);
|
||||||
|
|
||||||
//SetSizerAndFit( GetSizer(), false );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -58,24 +57,22 @@ FirstTimeWizard::UsermodePage::UsermodePage( wxWizard* parent ) :
|
||||||
{
|
{
|
||||||
SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||||
|
|
||||||
wxPanelWithHelpers* panel = new wxPanelWithHelpers( this, wxVERTICAL );
|
wxPanelWithHelpers& panel( *new wxPanelWithHelpers( this, wxVERTICAL ) );
|
||||||
panel->SetIdealWidth( 640 );
|
panel.SetIdealWidth( 640 );
|
||||||
wxSizer& s_panel( *panel->GetSizer() );
|
|
||||||
|
|
||||||
m_dirpick_settings = new SettingsDirPickerPanel( panel );
|
m_dirpick_settings = new SettingsDirPickerPanel( &panel );
|
||||||
m_panel_LangSel = new LanguageSelectionPanel( panel );
|
m_panel_LangSel = new LanguageSelectionPanel( &panel );
|
||||||
m_panel_UserSel = new UsermodeSelectionPanel( panel );
|
m_panel_UserSel = new UsermodeSelectionPanel( &panel );
|
||||||
|
|
||||||
(new pxStaticHeading( panel, _("PCSX2 is starting from a new or unknown folder and needs to be configured.") ))
|
panel += panel.Heading(_("PCSX2 is starting from a new or unknown folder and needs to be configured."));
|
||||||
->AddTo( s_panel );
|
|
||||||
|
|
||||||
s_panel.Add( m_panel_LangSel, pxSizerFlags::StdCenter() );
|
panel += m_panel_LangSel | StdCenter();
|
||||||
s_panel.Add( m_panel_UserSel, wxSizerFlags().Expand().Border( wxALL, 8 ) );
|
panel += m_panel_UserSel | pxExpand.Border( wxALL, 8 );
|
||||||
|
|
||||||
s_panel.AddSpacer( 6 );
|
panel += 6;
|
||||||
s_panel.Add( m_dirpick_settings, pxSizerFlags::SubGroup() );
|
panel += m_dirpick_settings | SubGroup();
|
||||||
|
|
||||||
GetSizer()->Add( panel, wxSizerFlags().Expand() );
|
panel += panel | pxExpand;
|
||||||
|
|
||||||
Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(FirstTimeWizard::UsermodePage::OnUsermodeChanged) );
|
Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler(FirstTimeWizard::UsermodePage::OnUsermodeChanged) );
|
||||||
}
|
}
|
||||||
|
@ -98,14 +95,13 @@ FirstTimeWizard::FirstTimeWizard( wxWindow* parent )
|
||||||
, m_panel_BiosSel ( MakeWizWidget<BiosSelectorPanel>( 2, &m_page_bios ) )
|
, m_panel_BiosSel ( MakeWizWidget<BiosSelectorPanel>( 2, &m_page_bios ) )
|
||||||
{
|
{
|
||||||
// Page 2 - Plugins Panel
|
// Page 2 - Plugins Panel
|
||||||
wxBoxSizer& pluginSizer( *new wxBoxSizer( wxVERTICAL ) );
|
|
||||||
pluginSizer.Add( &m_panel_PluginSel, pxSizerFlags::StdExpand() );
|
|
||||||
m_page_plugins.SetSizer( &pluginSizer );
|
|
||||||
|
|
||||||
// Page 3 - Bios Panel
|
// Page 3 - Bios Panel
|
||||||
wxBoxSizer& biosSizer( *new wxBoxSizer( wxVERTICAL ) );
|
|
||||||
biosSizer.Add( &m_panel_BiosSel, pxSizerFlags::StdExpand() );
|
m_page_plugins. SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||||
m_page_bios.SetSizer( &biosSizer );
|
m_page_bios. SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||||
|
|
||||||
|
m_page_plugins += m_panel_PluginSel | StdExpand();
|
||||||
|
m_page_bios += m_panel_BiosSel | StdExpand();
|
||||||
|
|
||||||
// Assign page indexes as client data
|
// Assign page indexes as client data
|
||||||
m_page_usermode.SetClientData ( (void*)0 );
|
m_page_usermode.SetClientData ( (void*)0 );
|
||||||
|
@ -117,8 +113,13 @@ FirstTimeWizard::FirstTimeWizard( wxWindow* parent )
|
||||||
m_page_usermode.SetNext ( &m_page_plugins );
|
m_page_usermode.SetNext ( &m_page_plugins );
|
||||||
m_page_plugins.SetNext ( &m_page_bios );
|
m_page_plugins.SetNext ( &m_page_bios );
|
||||||
|
|
||||||
GetPageAreaSizer()->Add( &m_page_usermode );
|
GetPageAreaSizer() += m_page_usermode;
|
||||||
GetPageAreaSizer()->Add( &m_page_plugins );
|
GetPageAreaSizer() += m_page_plugins;
|
||||||
|
|
||||||
|
// this doesn't descent from wxDialogWithHelpers, so we need to explicitly
|
||||||
|
// fit and center it. :(
|
||||||
|
|
||||||
|
Fit();
|
||||||
CenterOnScreen();
|
CenterOnScreen();
|
||||||
|
|
||||||
Connect( wxEVT_WIZARD_PAGE_CHANGED, wxWizardEventHandler( FirstTimeWizard::OnPageChanged ) );
|
Connect( wxEVT_WIZARD_PAGE_CHANGED, wxWizardEventHandler( FirstTimeWizard::OnPageChanged ) );
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
|
|
||||||
#include "ModalPopups.h"
|
#include "ModalPopups.h"
|
||||||
|
|
||||||
|
using namespace pxSizerFlags;
|
||||||
|
|
||||||
Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent )
|
Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent )
|
||||||
: wxDialogWithHelpers( parent, wxID_ANY, _("Import Existing Settings?"), false )
|
: wxDialogWithHelpers( parent, _("Import Existing Settings?"), wxVERTICAL )
|
||||||
{
|
{
|
||||||
m_idealWidth = 440;
|
m_idealWidth = 440;
|
||||||
|
|
||||||
|
@ -28,7 +30,6 @@ Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent )
|
||||||
L"Would you like to import these settings or overwrite them with PCSX2 default values?"
|
L"Would you like to import these settings or overwrite them with PCSX2 default values?"
|
||||||
L"\n\n(or press Cancel to select a different settings folder)" )
|
L"\n\n(or press Cancel to select a different settings folder)" )
|
||||||
);
|
);
|
||||||
heading->SetMinSize( wxSize( m_idealWidth-8, wxDefaultCoord ) );
|
|
||||||
|
|
||||||
wxBoxSizer& s_buttons = *new wxBoxSizer( wxHORIZONTAL );
|
wxBoxSizer& s_buttons = *new wxBoxSizer( wxHORIZONTAL );
|
||||||
wxButton* b_import = new wxButton( this, wxID_ANY, _("Import") );
|
wxButton* b_import = new wxButton( this, wxID_ANY, _("Import") );
|
||||||
|
@ -37,19 +38,16 @@ Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent )
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// Layout Some Shizat...
|
// Layout Some Shizat...
|
||||||
|
|
||||||
wxBoxSizer& sizer( *new wxBoxSizer( wxVERTICAL ) );
|
s_buttons += b_import | StdButton();
|
||||||
|
s_buttons += 16;
|
||||||
|
s_buttons += b_over | StdButton();
|
||||||
|
s_buttons += 16;
|
||||||
|
s_buttons += new wxButton( this, wxID_CANCEL ) | StdButton();
|
||||||
|
|
||||||
s_buttons.Add( b_import,pxSizerFlags::StdButton() );
|
*this += 4;
|
||||||
s_buttons.AddSpacer( 16 );
|
*this += heading;
|
||||||
s_buttons.Add( b_over, pxSizerFlags::StdButton() );
|
*this += 12;
|
||||||
s_buttons.AddSpacer( 16 );
|
*this += &s_buttons | StdCenter();
|
||||||
s_buttons.Add( new wxButton( this, wxID_CANCEL ), pxSizerFlags::StdButton() );
|
|
||||||
|
|
||||||
sizer.AddSpacer( 4 );
|
|
||||||
heading->AddTo( sizer );
|
|
||||||
sizer.AddSpacer( 12 );
|
|
||||||
sizer.Add( &s_buttons, pxSizerFlags::StdCenter() );
|
|
||||||
SetSizerAndFit( &sizer );
|
|
||||||
|
|
||||||
Connect( b_import->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ImportSettingsDialog::OnImport_Click) );
|
Connect( b_import->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ImportSettingsDialog::OnImport_Click) );
|
||||||
Connect( b_over->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ImportSettingsDialog::OnOverwrite_Click) );
|
Connect( b_over->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ImportSettingsDialog::OnOverwrite_Click) );
|
||||||
|
|
|
@ -21,9 +21,11 @@
|
||||||
|
|
||||||
using namespace Panels;
|
using namespace Panels;
|
||||||
|
|
||||||
Dialogs::LogOptionsDialog::LogOptionsDialog( wxWindow* parent, int id )
|
Dialogs::LogOptionsDialog::LogOptionsDialog( wxWindow* parent )
|
||||||
: wxDialogWithHelpers( parent, id, _("High Volume Logging"), true )
|
: wxDialogWithHelpers( parent, _("Trace Logging"), true )
|
||||||
{
|
{
|
||||||
|
SetName( GetNameStatic() );
|
||||||
|
|
||||||
m_idealWidth = 480;
|
m_idealWidth = 480;
|
||||||
|
|
||||||
wxBoxSizer& mainsizer = *new wxBoxSizer( wxVERTICAL );
|
wxBoxSizer& mainsizer = *new wxBoxSizer( wxVERTICAL );
|
||||||
|
|
|
@ -28,8 +28,11 @@ namespace Dialogs {
|
||||||
class LogOptionsDialog: public wxDialogWithHelpers
|
class LogOptionsDialog: public wxDialogWithHelpers
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LogOptionsDialog( wxWindow* parent=NULL, int id=DialogId_LogOptions );
|
LogOptionsDialog( wxWindow* parent=NULL );
|
||||||
|
virtual ~LogOptionsDialog() throw() { }
|
||||||
|
|
||||||
|
static const wxChar* GetNameStatic() { return L"Dialog:TraceLogSettings"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnOk_Click( wxCommandEvent& evt );
|
void OnOk_Click( wxCommandEvent& evt );
|
||||||
void OnApply_Click( wxCommandEvent& evt );
|
void OnApply_Click( wxCommandEvent& evt );
|
||||||
|
|
|
@ -66,7 +66,7 @@ protected:
|
||||||
virtual void OnDoubleClicked( wxCommandEvent& evt );
|
virtual void OnDoubleClicked( wxCommandEvent& evt );
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfButtons
|
class MsgButtons
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
BITFIELD32()
|
BITFIELD32()
|
||||||
|
@ -87,29 +87,29 @@ protected:
|
||||||
wxString m_CustomLabel;
|
wxString m_CustomLabel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConfButtons() : bitset( 0 ) { }
|
MsgButtons() : bitset( 0 ) { }
|
||||||
|
|
||||||
ConfButtons& OK() { m_OK = true; return *this; }
|
MsgButtons& OK() { m_OK = true; return *this; }
|
||||||
ConfButtons& Cancel() { m_Cancel = true; return *this; }
|
MsgButtons& Cancel() { m_Cancel = true; return *this; }
|
||||||
ConfButtons& Apply() { m_Apply = true; return *this; }
|
MsgButtons& Apply() { m_Apply = true; return *this; }
|
||||||
ConfButtons& Yes() { m_Yes = true; return *this; }
|
MsgButtons& Yes() { m_Yes = true; return *this; }
|
||||||
ConfButtons& No() { m_No = true; return *this; }
|
MsgButtons& No() { m_No = true; return *this; }
|
||||||
ConfButtons& ToAll() { m_AllowToAll = true; return *this; }
|
MsgButtons& ToAll() { m_AllowToAll = true; return *this; }
|
||||||
|
|
||||||
ConfButtons& Abort() { m_Abort = true; return *this; }
|
MsgButtons& Abort() { m_Abort = true; return *this; }
|
||||||
ConfButtons& Retry() { m_Retry = true; return *this; }
|
MsgButtons& Retry() { m_Retry = true; return *this; }
|
||||||
ConfButtons& Ignore() { m_Ignore = true; return *this; }
|
MsgButtons& Ignore() { m_Ignore = true; return *this; }
|
||||||
ConfButtons& Reset() { m_Reset = true; return *this; }
|
MsgButtons& Reset() { m_Reset = true; return *this; }
|
||||||
ConfButtons& Close() { m_Close = true; return *this; }
|
MsgButtons& Close() { m_Close = true; return *this; }
|
||||||
|
|
||||||
ConfButtons& Custom( const wxString& label)
|
MsgButtons& Custom( const wxString& label)
|
||||||
{
|
{
|
||||||
m_CustomLabel = label;
|
m_CustomLabel = label;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfButtons& OKCancel() { m_OK = m_Cancel = true; return *this; }
|
MsgButtons& OKCancel() { m_OK = m_Cancel = true; return *this; }
|
||||||
ConfButtons& YesNo() { m_Yes = m_No = true; return *this; }
|
MsgButtons& YesNo() { m_Yes = m_No = true; return *this; }
|
||||||
|
|
||||||
bool HasOK() const { return m_OK; }
|
bool HasOK() const { return m_OK; }
|
||||||
bool HasCancel() const { return m_Cancel; }
|
bool HasCancel() const { return m_Cancel; }
|
||||||
|
@ -128,29 +128,45 @@ public:
|
||||||
const wxString& GetCustomLabel() const { return m_CustomLabel; }
|
const wxString& GetCustomLabel() const { return m_CustomLabel; }
|
||||||
|
|
||||||
bool Allows( wxWindowID id ) const;
|
bool Allows( wxWindowID id ) const;
|
||||||
|
void SetBestFocus( wxWindow* dialog ) const;
|
||||||
|
void SetBestFocus( wxWindow& dialog ) const;
|
||||||
|
|
||||||
bool operator ==( const ConfButtons& right ) const
|
bool operator ==( const MsgButtons& right ) const
|
||||||
{
|
{
|
||||||
return OpEqu( bitset );
|
return OpEqu( bitset );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator !=( const ConfButtons& right ) const
|
bool operator !=( const MsgButtons& right ) const
|
||||||
{
|
{
|
||||||
return !OpEqu( bitset );
|
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
|
namespace Dialogs
|
||||||
{
|
{
|
||||||
class AboutBoxDialog: public wxDialogWithHelpers
|
class AboutBoxDialog: public wxDialogWithHelpers
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
AboutBoxDialog( wxWindow* parent=NULL, int id=DialogId_About );
|
|
||||||
virtual ~AboutBoxDialog() throw() {}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//wxStaticBitmap m_bitmap_logo;
|
//wxStaticBitmap m_bitmap_logo;
|
||||||
wxStaticBitmap m_bitmap_dualshock;
|
wxStaticBitmap m_bitmap_dualshock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AboutBoxDialog( wxWindow* parent=NULL );
|
||||||
|
virtual ~AboutBoxDialog() throw() {}
|
||||||
|
|
||||||
|
static const wxChar* GetNameStatic() { return L"Dialog:AboutBox"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,7 +177,7 @@ namespace Dialogs
|
||||||
Panels::LanguageSelectionPanel* m_panel_langsel;
|
Panels::LanguageSelectionPanel* m_panel_langsel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PickUserModeDialog( wxWindow* parent, int id=wxID_ANY );
|
PickUserModeDialog( wxWindow* parent );
|
||||||
virtual ~PickUserModeDialog() throw() {}
|
virtual ~PickUserModeDialog() throw() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -180,42 +196,15 @@ namespace Dialogs
|
||||||
void OnOverwrite_Click( wxCommandEvent& evt );
|
void OnOverwrite_Click( wxCommandEvent& evt );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AssertionDialog : public wxDialogWithHelpers
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// ExtensibleConfirmation Dialog
|
|
||||||
// --------------------------------------------------------------------------------------
|
|
||||||
// Purpose: This dialog is a simple framework for providing common popups that have three
|
|
||||||
// main sections of content:
|
|
||||||
//
|
|
||||||
// [Upper Paragraph]
|
|
||||||
// [Optional Interior Content]
|
|
||||||
// [OK] [CANCEL] [ETC]
|
|
||||||
//
|
|
||||||
// The Upper Paragraph and buttons are specified in the constructor. The Interior Content
|
|
||||||
// can be added by fetching the ExtensibleSizer provided by th created dialog. Add your
|
|
||||||
// content, dance around a bit, call Fit(), and then ShowModal. :)
|
|
||||||
|
|
||||||
class ExtensibleConfirmation : public wxDialogWithHelpers
|
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
wxBoxSizer& m_ExtensibleSizer;
|
|
||||||
wxBoxSizer& m_ButtonSizer;
|
|
||||||
|
|
||||||
ConfButtons m_Buttons;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExtensibleConfirmation( wxWindow* parent, const ConfButtons& type, const wxString& title, const wxString& msg );
|
AssertionDialog( const wxString& text, const wxString& stacktrace );
|
||||||
virtual ~ExtensibleConfirmation() throw() {}
|
virtual ~AssertionDialog() throw() {}
|
||||||
|
|
||||||
const ConfButtons& GetButtons() const { return m_Buttons; }
|
|
||||||
virtual wxBoxSizer& GetExtensibleSizer() const { return m_ExtensibleSizer; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void AddActionButton( wxWindowID id );
|
|
||||||
virtual void AddCustomButton( wxWindowID id, const wxString& label );
|
|
||||||
virtual void OnActionButtonClicked( wxCommandEvent& evt );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
wxWindowID IssueConfirmation( ExtensibleConfirmation& confirmDlg, const wxString& disablerKey );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxWindowID pxIssueConfirmation( wxDialogWithHelpers& confirmDlg, const MsgButtons& buttons );
|
||||||
|
wxWindowID pxIssueConfirmation( wxDialogWithHelpers& confirmDlg, const MsgButtons& buttons, const wxString& disablerKey );
|
||||||
|
|
|
@ -20,21 +20,17 @@
|
||||||
|
|
||||||
using namespace Panels;
|
using namespace Panels;
|
||||||
|
|
||||||
Dialogs::PickUserModeDialog::PickUserModeDialog( wxWindow* parent, int id )
|
Dialogs::PickUserModeDialog::PickUserModeDialog( wxWindow* parent )
|
||||||
: wxDialogWithHelpers( parent, id, _("PCSX2 First Time configuration"), false )
|
: wxDialogWithHelpers( parent, _("PCSX2 First Time configuration"), wxVERTICAL )
|
||||||
{
|
{
|
||||||
m_panel_usersel = new UsermodeSelectionPanel( this, false );
|
m_panel_usersel = new UsermodeSelectionPanel( this, false );
|
||||||
m_panel_langsel = new LanguageSelectionPanel( this );
|
m_panel_langsel = new LanguageSelectionPanel( this );
|
||||||
|
|
||||||
SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
|
||||||
|
|
||||||
*this += new pxStaticHeading( this, _("PCSX2 is starting from a new or unknown folder and needs to be configured.") );
|
*this += new pxStaticHeading( this, _("PCSX2 is starting from a new or unknown folder and needs to be configured.") );
|
||||||
*this += m_panel_langsel | pxSizerFlags::StdCenter();
|
*this += m_panel_langsel | pxSizerFlags::StdCenter();
|
||||||
*this += m_panel_usersel | wxSizerFlags().Expand().Border( wxALL, 8 );
|
*this += m_panel_usersel | wxSizerFlags().Expand().Border( wxALL, 8 );
|
||||||
|
|
||||||
AddOkCancel( *GetSizer() );
|
AddOkCancel( *GetSizer() );
|
||||||
Fit();
|
|
||||||
CenterOnScreen();
|
|
||||||
|
|
||||||
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PickUserModeDialog::OnOk_Click ) );
|
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PickUserModeDialog::OnOk_Click ) );
|
||||||
// TODO : Add a command event handler for language changes, that dynamically re-update contents of this window.
|
// TODO : Add a command event handler for language changes, that dynamically re-update contents of this window.
|
||||||
|
|
|
@ -49,8 +49,9 @@ GSPanel::GSPanel( wxWindow* parent )
|
||||||
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
|
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
|
||||||
, m_HideMouseTimer( this )
|
, m_HideMouseTimer( this )
|
||||||
{
|
{
|
||||||
m_CursorShown = true;
|
m_CursorShown = true;
|
||||||
|
m_HasFocus = false;
|
||||||
|
|
||||||
if ( !wxWindow::Create(parent, wxID_ANY) )
|
if ( !wxWindow::Create(parent, wxID_ANY) )
|
||||||
throw Exception::RuntimeError( "GSPanel constructor esplode!!" );
|
throw Exception::RuntimeError( "GSPanel constructor esplode!!" );
|
||||||
|
|
||||||
|
@ -68,6 +69,9 @@ GSPanel::GSPanel( wxWindow* parent )
|
||||||
Connect( wxEVT_SIZE, wxSizeEventHandler (GSPanel::OnResize) );
|
Connect( wxEVT_SIZE, wxSizeEventHandler (GSPanel::OnResize) );
|
||||||
Connect( wxEVT_KEY_DOWN, wxKeyEventHandler (GSPanel::OnKeyDown) );
|
Connect( wxEVT_KEY_DOWN, wxKeyEventHandler (GSPanel::OnKeyDown) );
|
||||||
|
|
||||||
|
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler(GSPanel::OnFocus) );
|
||||||
|
Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler(GSPanel::OnFocusLost) );
|
||||||
|
|
||||||
Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
||||||
Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
||||||
Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
||||||
|
@ -131,6 +135,7 @@ void GSPanel::DoResize()
|
||||||
|
|
||||||
void GSPanel::OnResize(wxSizeEvent& event)
|
void GSPanel::OnResize(wxSizeEvent& event)
|
||||||
{
|
{
|
||||||
|
if( IsBeingDeleted() ) return;
|
||||||
DoResize();
|
DoResize();
|
||||||
//Console.Error( "Size? %d x %d", GetSize().x, GetSize().y );
|
//Console.Error( "Size? %d x %d", GetSize().x, GetSize().y );
|
||||||
//event.
|
//event.
|
||||||
|
@ -144,12 +149,14 @@ void GSPanel::OnCloseWindow(wxCloseEvent& evt)
|
||||||
|
|
||||||
void GSPanel::OnShowMouse( wxMouseEvent& evt )
|
void GSPanel::OnShowMouse( wxMouseEvent& evt )
|
||||||
{
|
{
|
||||||
|
if( IsBeingDeleted() ) return;
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
DoShowMouse();
|
DoShowMouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSPanel::OnHideMouseTimeout( wxTimerEvent& evt )
|
void GSPanel::OnHideMouseTimeout( wxTimerEvent& evt )
|
||||||
{
|
{
|
||||||
|
if( IsBeingDeleted() || !m_HasFocus ) return;
|
||||||
if( CoreThread.GetExecutionMode() != SysThreadBase::ExecMode_Opened ) return;
|
if( CoreThread.GetExecutionMode() != SysThreadBase::ExecMode_Opened ) return;
|
||||||
|
|
||||||
SetCursor( wxCursor( wxCURSOR_BLANK ) );
|
SetCursor( wxCursor( wxCURSOR_BLANK ) );
|
||||||
|
@ -180,6 +187,26 @@ void GSPanel::OnKeyDown( wxKeyEvent& evt )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GSPanel::OnFocus( wxFocusEvent& evt )
|
||||||
|
{
|
||||||
|
evt.Skip();
|
||||||
|
m_HasFocus = true;
|
||||||
|
|
||||||
|
if( g_Conf->GSWindow.AlwaysHideMouse )
|
||||||
|
{
|
||||||
|
SetCursor( wxCursor(wxCURSOR_BLANK) );
|
||||||
|
m_CursorShown = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DoShowMouse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSPanel::OnFocusLost( wxFocusEvent& evt )
|
||||||
|
{
|
||||||
|
evt.Skip();
|
||||||
|
m_HasFocus = false;
|
||||||
|
DoShowMouse();
|
||||||
|
}
|
||||||
|
|
||||||
void __evt_fastcall GSPanel::OnSettingsApplied( void* obj, int& evt )
|
void __evt_fastcall GSPanel::OnSettingsApplied( void* obj, int& evt )
|
||||||
{
|
{
|
||||||
|
@ -234,12 +261,18 @@ wxWindow* GSFrame::GetViewport()
|
||||||
|
|
||||||
void GSFrame::OnActivate( wxActivateEvent& evt )
|
void GSFrame::OnActivate( wxActivateEvent& evt )
|
||||||
{
|
{
|
||||||
|
if( IsBeingDeleted() ) return;
|
||||||
|
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
if( wxWindow* gsPanel = FindWindowByName(L"GSPanel") ) gsPanel->SetFocus();
|
if( wxWindow* gsPanel = FindWindowByName(L"GSPanel") ) gsPanel->SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSFrame::OnMove( wxMoveEvent& evt )
|
void GSFrame::OnMove( wxMoveEvent& evt )
|
||||||
{
|
{
|
||||||
|
if( IsBeingDeleted() ) return;
|
||||||
|
|
||||||
|
evt.Skip();
|
||||||
|
|
||||||
// evt.GetPosition() returns the client area position, not the window frame position.
|
// evt.GetPosition() returns the client area position, not the window frame position.
|
||||||
if( !IsMaximized() && IsVisible() )
|
if( !IsMaximized() && IsVisible() )
|
||||||
g_Conf->GSWindow.WindowPos = GetScreenPosition();
|
g_Conf->GSWindow.WindowPos = GetScreenPosition();
|
||||||
|
|
|
@ -61,11 +61,7 @@ void IniInterface::Flush()
|
||||||
IniScopedGroup::IniScopedGroup( IniInterface& mommy, const wxString& group ) :
|
IniScopedGroup::IniScopedGroup( IniInterface& mommy, const wxString& group ) :
|
||||||
m_mom( mommy )
|
m_mom( mommy )
|
||||||
{
|
{
|
||||||
if( IsDevBuild )
|
pxAssertDev( wxStringTokenize( group, L"/" ).Count() <= 1, L"Cannot nest more than one group deep per instance of IniScopedGroup." );
|
||||||
{
|
|
||||||
if( wxStringTokenize( group, L"/" ).Count() > 1 )
|
|
||||||
throw Exception::InvalidArgument( "Cannot nest more than one group deep per instance of IniScopedGroup." );
|
|
||||||
}
|
|
||||||
m_mom.SetPath( group );
|
m_mom.SetPath( group );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,9 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen
|
||||||
|
|
||||||
if( filenames.GetCount() > 1 )
|
if( filenames.GetCount() > 1 )
|
||||||
{
|
{
|
||||||
Dialogs::ExtensibleConfirmation( m_WindowBound, ConfButtons().Cancel(),
|
wxDialogWithHelpers dialog( m_WindowBound, _("Drag and Drop Error"), wxVERTICAL );
|
||||||
_("Drag and Drop Error"),
|
dialog += dialog.Heading( _("It is an error to drop multiple files onto a PCSX2 window. One at a time please, thank you.") );
|
||||||
_("It is an error to drop multiple files onto a PCSX2 window. One at a time please, thank you.")
|
pxIssueConfirmation( dialog, MsgButtons().Cancel() );
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,13 +68,14 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen
|
||||||
bool confirmed = true;
|
bool confirmed = true;
|
||||||
if( SysHasValidState() )
|
if( SysHasValidState() )
|
||||||
{
|
{
|
||||||
Dialogs::ExtensibleConfirmation dialog( m_WindowBound, ConfButtons().Reset().Cancel(),
|
wxDialogWithHelpers dialog( m_WindowBound, _("Confirm PS2 Reset"), wxVERTICAL );
|
||||||
_("Confirm PS2 Reset"),
|
|
||||||
|
dialog += dialog.Heading(
|
||||||
_("You have dropped the following ELF binary into PCSX2:\n\n") +
|
_("You have dropped the following ELF binary into PCSX2:\n\n") +
|
||||||
filenames[0] + L"\n\n" + GetMsg_ConfirmSysReset()
|
filenames[0] + L"\n\n" + GetMsg_ConfirmSysReset()
|
||||||
);
|
);
|
||||||
|
|
||||||
confirmed = (Dialogs::IssueConfirmation( dialog, L"DragDrop:BootELF" ) != wxID_CANCEL);
|
confirmed = (pxIssueConfirmation( dialog, MsgButtons().Reset().Cancel(), L"DragDrop:BootELF" ) != wxID_CANCEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( confirmed )
|
if( confirmed )
|
||||||
|
@ -111,14 +111,14 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen
|
||||||
|
|
||||||
if( SysHasValidState() )
|
if( SysHasValidState() )
|
||||||
{
|
{
|
||||||
Dialogs::ExtensibleConfirmation dialog( m_WindowBound, ConfButtons().Reset().Cancel().Custom(_("Swap Disc")),
|
wxDialogWithHelpers dialog( m_WindowBound, _("Confirm PS2 Reset"), wxVERTICAL );
|
||||||
_("Confirm PS2 Reset"),
|
|
||||||
_("You have dropped the following ISO image into PCSX2:\n\n") +
|
dialog += dialog.Heading(_("You have dropped the following ISO image into PCSX2:\n\n") +
|
||||||
filenames[0] + L"\n\n" +
|
filenames[0] + L"\n\n" +
|
||||||
_("Do you want to swap discs or boot the new image (via system reset)?")
|
_("Do you want to swap discs or boot the new image (via system reset)?")
|
||||||
);
|
);
|
||||||
|
|
||||||
result = Dialogs::IssueConfirmation( dialog, L"DragDrop:BootIso" );
|
result = pxIssueConfirmation( dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc")), L"DragDrop:BootIso" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( result != wxID_CANCEL )
|
if( result != wxID_CANCEL )
|
||||||
|
|
|
@ -31,6 +31,7 @@ protected:
|
||||||
EventListenerBinding<int> m_Listener_SettingsApplied;
|
EventListenerBinding<int> m_Listener_SettingsApplied;
|
||||||
wxTimer m_HideMouseTimer;
|
wxTimer m_HideMouseTimer;
|
||||||
bool m_CursorShown;
|
bool m_CursorShown;
|
||||||
|
bool m_HasFocus;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GSPanel( wxWindow* parent );
|
GSPanel( wxWindow* parent );
|
||||||
|
@ -49,6 +50,8 @@ protected:
|
||||||
void OnShowMouse( wxMouseEvent& evt );
|
void OnShowMouse( wxMouseEvent& evt );
|
||||||
void OnHideMouseTimeout( wxTimerEvent& evt );
|
void OnHideMouseTimeout( wxTimerEvent& evt );
|
||||||
void OnKeyDown( wxKeyEvent& evt );
|
void OnKeyDown( wxKeyEvent& evt );
|
||||||
|
void OnFocus( wxFocusEvent& evt );
|
||||||
|
void OnFocusLost( wxFocusEvent& evt );
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -28,6 +28,15 @@
|
||||||
|
|
||||||
using namespace Dialogs;
|
using namespace Dialogs;
|
||||||
|
|
||||||
|
template<typename DialogType>
|
||||||
|
void AppOpenDialog( wxWindow* parent )
|
||||||
|
{
|
||||||
|
if( wxWindow* window = wxFindWindowByName( DialogType::GetNameStatic() ) )
|
||||||
|
window->SetFocus();
|
||||||
|
else
|
||||||
|
(new DialogType( parent ))->Show();
|
||||||
|
}
|
||||||
|
|
||||||
extern wxString GetMsg_ConfirmSysReset();
|
extern wxString GetMsg_ConfirmSysReset();
|
||||||
|
|
||||||
void MainEmuFrame::SaveEmuOptions()
|
void MainEmuFrame::SaveEmuOptions()
|
||||||
|
@ -41,12 +50,12 @@ void MainEmuFrame::SaveEmuOptions()
|
||||||
|
|
||||||
void MainEmuFrame::Menu_ConfigSettings_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_ConfigSettings_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
Dialogs::ConfigurationDialog( this ).ShowModal();
|
AppOpenDialog<ConfigurationDialog>( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_SelectBios_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_SelectBios_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
Dialogs::BiosSelectorDialog( this ).ShowModal();
|
AppOpenDialog<BiosSelectorDialog>( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_CdvdSource_Click( wxCommandEvent &event )
|
void MainEmuFrame::Menu_CdvdSource_Click( wxCommandEvent &event )
|
||||||
|
@ -118,11 +127,14 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
||||||
// User has an iso selected from a previous run, but it doesn't exist anymore.
|
// User has an iso selected from a previous run, but it doesn't exist anymore.
|
||||||
// Issue a courtesy popup and then an Iso Selector to choose a new one.
|
// Issue a courtesy popup and then an Iso Selector to choose a new one.
|
||||||
|
|
||||||
Dialogs::ExtensibleConfirmation( this, ConfButtons().OK(), _("ISO file not found!"),
|
wxDialogWithHelpers dialog( this, _("ISO file not found!"), wxVERTICAL );
|
||||||
|
dialog += dialog.Heading(
|
||||||
_("An error occurred while trying to open the file:\n\n") + g_Conf->CurrentIso + L"\n\n" +
|
_("An error occurred while trying to open the file:\n\n") + g_Conf->CurrentIso + L"\n\n" +
|
||||||
_("Error: The configured ISO file does not exist. Click OK to select a new ISO source for CDVD.")
|
_("Error: The configured ISO file does not exist. Click OK to select a new ISO source for CDVD.")
|
||||||
).ShowModal();
|
);
|
||||||
|
|
||||||
|
pxIssueConfirmation( dialog, MsgButtons().OK() );
|
||||||
|
|
||||||
selector = true;
|
selector = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,11 +153,9 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
||||||
|
|
||||||
if( SysHasValidState() )
|
if( SysHasValidState() )
|
||||||
{
|
{
|
||||||
ExtensibleConfirmation dialog( this, ConfButtons().Yes().Cancel(),
|
wxDialogWithHelpers dialog( this, _("Confirm PS2 Reset"), wxVERTICAL );
|
||||||
_("Confirm PS2 Reset"), GetMsg_ConfirmSysReset()
|
dialog += dialog.Heading( GetMsg_ConfirmSysReset() );
|
||||||
);
|
bool confirmed = (pxIssueConfirmation( dialog, MsgButtons().Yes().Cancel(), L"BootCdvd:ConfirmReset" ) != wxID_CANCEL);
|
||||||
|
|
||||||
bool confirmed = (IssueConfirmation( dialog, L"BootCdvd:ConfirmReset" ) != wxID_CANCEL);
|
|
||||||
|
|
||||||
if( !confirmed )
|
if( !confirmed )
|
||||||
{
|
{
|
||||||
|
@ -290,7 +300,7 @@ void MainEmuFrame::Menu_Debug_MemoryDump_Click(wxCommandEvent &event)
|
||||||
|
|
||||||
void MainEmuFrame::Menu_Debug_Logging_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_Debug_Logging_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
LogOptionsDialog( this, wxID_ANY ).ShowModal();
|
AppOpenDialog<LogOptionsDialog>( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainEmuFrame::Menu_ShowConsole(wxCommandEvent &event)
|
void MainEmuFrame::Menu_ShowConsole(wxCommandEvent &event)
|
||||||
|
@ -316,5 +326,5 @@ void MainEmuFrame::Menu_PrintCDVD_Info(wxCommandEvent &event)
|
||||||
|
|
||||||
void MainEmuFrame::Menu_ShowAboutBox(wxCommandEvent &event)
|
void MainEmuFrame::Menu_ShowAboutBox(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
AboutBoxDialog( this, wxID_ANY ).ShowModal();
|
AppOpenDialog<AboutBoxDialog>( this );
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,130 +15,277 @@
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "App.h"
|
#include "App.h"
|
||||||
|
#include "Dialogs/ModalPopups.h"
|
||||||
|
|
||||||
DEFINE_EVENT_TYPE( pxEVT_MSGBOX );
|
DEFINE_EVENT_TYPE( pxEVT_MSGBOX );
|
||||||
DEFINE_EVENT_TYPE( pxEVT_CallStackBox );
|
DEFINE_EVENT_TYPE( pxEVT_ASSERTION );
|
||||||
|
|
||||||
using namespace Threading;
|
using namespace Threading;
|
||||||
|
using namespace pxSizerFlags;
|
||||||
|
|
||||||
// Thread Safety: Must be called from the GUI thread ONLY.
|
// Thread Safety: Must be called from the GUI thread ONLY. Will assert otherwise.
|
||||||
static int pxMessageDialog( const wxString& content, const wxString& caption, long flags )
|
//
|
||||||
|
// [TODO] Add support for icons?
|
||||||
|
//
|
||||||
|
static int pxMessageDialog( const wxString& caption, const wxString& content, const MsgButtons& buttons )
|
||||||
{
|
{
|
||||||
if( IsDevBuild && !wxThread::IsMain() )
|
if( !AffinityAssert_AllowFromMain() ) return wxID_CANCEL;
|
||||||
throw Exception::InvalidOperation( "Function must be called by the main GUI thread only." );
|
|
||||||
|
|
||||||
// fixme: If the emulator is currently active and is running in fullscreen mode, then we
|
// fixme: If the emulator is currently active and is running in exclusive mode (forced
|
||||||
// need to either:
|
// fullscreen), then we need to either:
|
||||||
// 1) Exit fullscreen mode before issuing the popup.
|
// 1) Exit fullscreen mode before issuing the popup.
|
||||||
// 2) Issue the popup with wxSTAY_ON_TOP specified so that the user will see it.
|
// 2) Issue the popup with wxSTAY_ON_TOP specified so that the user will see it.
|
||||||
//
|
//
|
||||||
// And in either case the emulation should be paused/suspended for the user.
|
// And in either case the emulation should be paused/suspended for the user.
|
||||||
|
|
||||||
return wxMessageDialog( NULL, content, caption, flags ).ShowModal();
|
wxDialogWithHelpers dialog( NULL, caption, wxVERTICAL );
|
||||||
|
dialog += dialog.Heading( content );
|
||||||
|
return pxIssueConfirmation( dialog, buttons );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread Safety: Must be called from the GUI thread ONLY.
|
class BaseMessageBoxEvent : public wxEvent
|
||||||
// fixme: this function should use a custom dialog box that has a wxTextCtrl for the callstack, and
|
|
||||||
// uses fixed-width (modern) fonts.
|
|
||||||
static int pxCallstackDialog( const wxString& content, const wxString& caption, long flags )
|
|
||||||
{
|
{
|
||||||
if( IsDevBuild && !wxThread::IsMain() )
|
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent)
|
||||||
throw Exception::InvalidOperation( "Function must be called by the main GUI thread only." );
|
|
||||||
|
|
||||||
return wxMessageDialog( NULL, content, caption, flags ).ShowModal();
|
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
|
// pxMessageBoxEvent
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
class pxMessageBoxEvent : public wxEvent
|
// 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
|
||||||
{
|
{
|
||||||
protected:
|
typedef BaseMessageBoxEvent _parent;
|
||||||
MsgboxEventResult& m_Instdata;
|
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent)
|
||||||
wxString m_Title;
|
|
||||||
wxString m_Content;
|
|
||||||
long m_Flags;
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
wxString m_Title;
|
||||||
|
MsgButtons m_Buttons;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pxMessageBoxEvent()
|
pxMessageBoxEvent( int msgtype=pxEVT_MSGBOX )
|
||||||
: wxEvent( 0, pxEVT_MSGBOX )
|
: BaseMessageBoxEvent( msgtype )
|
||||||
, m_Instdata( *(MsgboxEventResult*)NULL )
|
|
||||||
, m_Title()
|
|
||||||
, m_Content()
|
|
||||||
{
|
{
|
||||||
m_Flags = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pxMessageBoxEvent( MsgboxEventResult& instdata, const wxString& title, const wxString& content, long flags )
|
virtual ~pxMessageBoxEvent() throw() { }
|
||||||
: wxEvent( 0, pxEVT_MSGBOX )
|
virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
|
||||||
, m_Instdata( instdata )
|
|
||||||
|
pxMessageBoxEvent( MsgboxEventResult& instdata, const wxString& title, const wxString& content, const MsgButtons& buttons )
|
||||||
|
: BaseMessageBoxEvent( instdata, content )
|
||||||
, m_Title( title )
|
, m_Title( title )
|
||||||
, m_Content( content )
|
, m_Buttons( buttons )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
pxMessageBoxEvent( const wxString& title, const wxString& content, const MsgButtons& buttons )
|
||||||
|
: BaseMessageBoxEvent( content )
|
||||||
|
, m_Title( title )
|
||||||
|
, m_Buttons( buttons )
|
||||||
{
|
{
|
||||||
m_Flags = flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pxMessageBoxEvent( const pxMessageBoxEvent& event )
|
pxMessageBoxEvent( const pxMessageBoxEvent& event )
|
||||||
: wxEvent( event )
|
: BaseMessageBoxEvent( event )
|
||||||
, m_Instdata( event.m_Instdata )
|
|
||||||
, m_Title( event.m_Title )
|
, m_Title( event.m_Title )
|
||||||
, m_Content( event.m_Content )
|
, m_Buttons( event.m_Buttons )
|
||||||
{
|
{
|
||||||
m_Flags = event.m_Flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread Safety: Must be called from the GUI thread ONLY.
|
pxMessageBoxEvent& SetInstData( MsgboxEventResult& instdata )
|
||||||
void DoTheDialog()
|
|
||||||
{
|
{
|
||||||
int result;
|
_parent::SetInstData( instdata );
|
||||||
|
return *this;
|
||||||
if( m_id == pxEVT_MSGBOX )
|
|
||||||
result = pxMessageDialog( m_Content, m_Title, m_Flags );
|
|
||||||
else
|
|
||||||
result = pxCallstackDialog( m_Content, m_Title, m_Flags );
|
|
||||||
m_Instdata.result = result;
|
|
||||||
m_Instdata.WaitForMe.Post();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual wxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
|
protected:
|
||||||
|
virtual int _DoDialog() const
|
||||||
private:
|
{
|
||||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent)
|
return pxMessageDialog( m_Content, m_Title, m_Buttons );
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IMPLEMENT_DYNAMIC_CLASS( pxMessageBoxEvent, wxEvent )
|
// --------------------------------------------------------------------------------------
|
||||||
|
// 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 )
|
||||||
|
IMPLEMENT_DYNAMIC_CLASS( pxMessageBoxEvent, BaseMessageBoxEvent )
|
||||||
|
IMPLEMENT_DYNAMIC_CLASS( pxAssertionEvent, BaseMessageBoxEvent )
|
||||||
|
|
||||||
namespace Msgbox
|
namespace Msgbox
|
||||||
{
|
{
|
||||||
// parameters:
|
static int ThreadedMessageBox( BaseMessageBoxEvent& evt )
|
||||||
// flags - messagebox type flags, such as wxOK, wxCANCEL, etc.
|
{
|
||||||
//
|
MsgboxEventResult instdat;
|
||||||
static int ThreadedMessageBox( const wxString& content, const wxString& title, long flags, int boxType=pxEVT_MSGBOX )
|
evt.SetInstData( instdat );
|
||||||
|
|
||||||
|
if( wxThread::IsMain() )
|
||||||
|
{
|
||||||
|
// main thread can handle the message immediately.
|
||||||
|
wxGetApp().ProcessEvent( evt );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not on main thread, must post the message there for handling instead:
|
||||||
|
wxGetApp().AddPendingEvent( evt );
|
||||||
|
instdat.WaitForMe.WaitNoCancel(); // Important! disable cancellation since we're using local stack vars.
|
||||||
|
}
|
||||||
|
return instdat.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ThreadedMessageBox( const wxString& title, const wxString& content, const MsgButtons& buttons )
|
||||||
{
|
{
|
||||||
// must pass the message to the main gui thread, and then stall this thread, to avoid
|
// must pass the message to the main gui thread, and then stall this thread, to avoid
|
||||||
// threaded chaos where our thread keeps running while the popup is awaiting input.
|
// threaded chaos where our thread keeps running while the popup is awaiting input.
|
||||||
|
|
||||||
MsgboxEventResult instdat;
|
MsgboxEventResult instdat;
|
||||||
pxMessageBoxEvent tevt( instdat, title, content, flags );
|
pxMessageBoxEvent tevt( instdat, title, content, buttons );
|
||||||
wxGetApp().AddPendingEvent( tevt );
|
wxGetApp().AddPendingEvent( tevt );
|
||||||
instdat.WaitForMe.WaitNoCancel(); // Important! disable cancellation since we're using local stack vars.
|
instdat.WaitForMe.WaitNoCancel(); // Important! disable cancellation since we're using local stack vars.
|
||||||
return instdat.result;
|
return instdat.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnEvent( pxMessageBoxEvent& evt )
|
|
||||||
{
|
|
||||||
evt.DoTheDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pops up an alert Dialog Box with a singular "OK" button.
|
// Pops up an alert Dialog Box with a singular "OK" button.
|
||||||
// Always returns false.
|
// Always returns false.
|
||||||
bool Alert( const wxString& text, const wxString& caption, int icon )
|
bool Alert( const wxString& text, const wxString& caption, int icon )
|
||||||
{
|
{
|
||||||
icon |= wxOK;
|
MsgButtons buttons( MsgButtons().OK() );
|
||||||
|
|
||||||
if( wxThread::IsMain() )
|
if( wxThread::IsMain() )
|
||||||
pxMessageDialog( text, caption, icon );
|
pxMessageDialog( caption, text, buttons );
|
||||||
else
|
else
|
||||||
ThreadedMessageBox( text, caption, icon );
|
ThreadedMessageBox( caption, text, buttons );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,60 +293,40 @@ namespace Msgbox
|
||||||
// true if OK, false if cancel.
|
// true if OK, false if cancel.
|
||||||
bool OkCancel( const wxString& text, const wxString& caption, int icon )
|
bool OkCancel( const wxString& text, const wxString& caption, int icon )
|
||||||
{
|
{
|
||||||
icon |= wxOK | wxCANCEL;
|
MsgButtons buttons( MsgButtons().OKCancel() );
|
||||||
|
|
||||||
if( wxThread::IsMain() )
|
if( wxThread::IsMain() )
|
||||||
{
|
{
|
||||||
return wxID_OK == pxMessageDialog( text, caption, icon );
|
return wxID_OK == pxMessageDialog( caption, text, buttons );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return wxID_OK == ThreadedMessageBox( text, caption, icon );
|
return wxID_OK == ThreadedMessageBox( caption, text, buttons );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool YesNo( const wxString& text, const wxString& caption, int icon )
|
bool YesNo( const wxString& text, const wxString& caption, int icon )
|
||||||
{
|
{
|
||||||
icon |= wxYES_NO;
|
MsgButtons buttons( MsgButtons().YesNo() );
|
||||||
if( wxThread::IsMain() )
|
|
||||||
{
|
|
||||||
return wxID_YES == pxMessageDialog( text, caption, icon );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return wxID_YES == ThreadedMessageBox( text, caption, icon );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [TODO] : This should probably be a fancier looking dialog box with the stacktrace
|
|
||||||
// displayed inside a wxTextCtrl.
|
|
||||||
static int CallStack( const wxString& errormsg, const wxString& stacktrace, const wxString& prompt, const wxString& caption, int buttons )
|
|
||||||
{
|
|
||||||
buttons |= wxICON_STOP;
|
|
||||||
|
|
||||||
wxString text( errormsg + L"\n\n" + stacktrace + L"\n" + prompt );
|
|
||||||
|
|
||||||
if( wxThread::IsMain() )
|
if( wxThread::IsMain() )
|
||||||
{
|
{
|
||||||
return pxCallstackDialog( text, caption, buttons );
|
return wxID_YES == pxMessageDialog( caption, text, buttons );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return ThreadedMessageBox( text, caption, buttons, pxEVT_CallStackBox );
|
return wxID_YES == ThreadedMessageBox( caption, text, buttons );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Assertion( const wxString& text, const wxString& stacktrace )
|
int Assertion( const wxString& text, const wxString& stacktrace )
|
||||||
{
|
{
|
||||||
return CallStack( text, stacktrace,
|
pxAssertionEvent tevt( text, stacktrace );
|
||||||
L"\nDo you want to stop the program?"
|
return ThreadedMessageBox( tevt );
|
||||||
L"\nOr press [Cancel] to suppress further assertions.",
|
|
||||||
L"PCSX2 Assertion Failure",
|
|
||||||
wxYES_NO | wxCANCEL
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Except( const Exception::BaseException& src )
|
|
||||||
{
|
|
||||||
CallStack( src.FormatDisplayMessage(), src.FormatDiagnosticMessage(), wxEmptyString, L"PCSX2 Unhandled Exception", wxOK );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt )
|
||||||
|
{
|
||||||
|
evt.IssueDialog();
|
||||||
|
}
|
||||||
|
|
|
@ -46,8 +46,8 @@ Panels::BaseAdvancedCpuOptions::BaseAdvancedCpuOptions( wxWindow* parent )
|
||||||
|
|
||||||
// Highlight Default Options:
|
// Highlight Default Options:
|
||||||
|
|
||||||
m_RoundModePanel->SetDefault( 3 );
|
m_RoundModePanel->SetDefaultItem( 3 );
|
||||||
m_ClampModePanel->SetDefault( 1 );
|
m_ClampModePanel->SetDefaultItem( 1 );
|
||||||
|
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
// The Fitting And Sizing Area
|
// The Fitting And Sizing Area
|
||||||
|
@ -146,8 +146,8 @@ Panels::CpuPanelEE::CpuPanelEE( wxWindow* parent )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
m_panel_RecEE = &(new pxRadioPanel( this, tbl_CpuTypes_EE ))->SetDefault( 1 );
|
m_panel_RecEE = &(new pxRadioPanel( this, tbl_CpuTypes_EE ))->SetDefaultItem( 1 );
|
||||||
m_panel_RecIOP = &(new pxRadioPanel( this, tbl_CpuTypes_IOP ))->SetDefault( 1 );
|
m_panel_RecIOP = &(new pxRadioPanel( this, tbl_CpuTypes_IOP ))->SetDefaultItem( 1 );
|
||||||
|
|
||||||
m_panel_RecEE->Realize();
|
m_panel_RecEE->Realize();
|
||||||
m_panel_RecIOP->Realize();
|
m_panel_RecIOP->Realize();
|
||||||
|
@ -193,8 +193,8 @@ Panels::CpuPanelVU::CpuPanelVU( wxWindow* parent )
|
||||||
.SetToolTip(_("Useful for diagnosing bugs or clamping issues in the new mVU recompiler."))
|
.SetToolTip(_("Useful for diagnosing bugs or clamping issues in the new mVU recompiler."))
|
||||||
};
|
};
|
||||||
|
|
||||||
m_panel_VU0 = &(new pxRadioPanel( this, tbl_CpuTypes_VU )) ->SetDefault( 1 );
|
m_panel_VU0 = &(new pxRadioPanel( this, tbl_CpuTypes_VU )) ->SetDefaultItem( 1 );
|
||||||
m_panel_VU1 = &(new pxRadioPanel( this, tbl_CpuTypes_VU )) ->SetDefault( 1 );
|
m_panel_VU1 = &(new pxRadioPanel( this, tbl_CpuTypes_VU )) ->SetDefaultItem( 1 );
|
||||||
|
|
||||||
m_panel_VU0->Realize();
|
m_panel_VU0->Realize();
|
||||||
m_panel_VU1->Realize();
|
m_panel_VU1->Realize();
|
||||||
|
@ -233,6 +233,9 @@ void Panels::CpuPanelEE::Apply()
|
||||||
|
|
||||||
void Panels::CpuPanelEE::OnSettingsChanged()
|
void Panels::CpuPanelEE::OnSettingsChanged()
|
||||||
{
|
{
|
||||||
|
m_panel_RecEE->Enable( x86caps.hasStreamingSIMD2Extensions );
|
||||||
|
m_panel_RecIOP->Enable( x86caps.hasStreamingSIMD2Extensions );
|
||||||
|
|
||||||
const Pcsx2Config::RecompilerOptions& recOps( g_Conf->EmuOptions.Cpu.Recompiler );
|
const Pcsx2Config::RecompilerOptions& recOps( g_Conf->EmuOptions.Cpu.Recompiler );
|
||||||
m_panel_RecEE->SetSelection( (int)recOps.EnableEE );
|
m_panel_RecEE->SetSelection( (int)recOps.EnableEE );
|
||||||
m_panel_RecIOP->SetSelection( (int)recOps.EnableIOP );
|
m_panel_RecIOP->SetSelection( (int)recOps.EnableIOP );
|
||||||
|
@ -250,6 +253,12 @@ void Panels::CpuPanelVU::Apply()
|
||||||
|
|
||||||
void Panels::CpuPanelVU::OnSettingsChanged()
|
void Panels::CpuPanelVU::OnSettingsChanged()
|
||||||
{
|
{
|
||||||
|
m_panel_VU0->EnableItem( 1, x86caps.hasStreamingSIMD2Extensions );
|
||||||
|
m_panel_VU0->EnableItem( 2, x86caps.hasStreamingSIMD2Extensions );
|
||||||
|
|
||||||
|
m_panel_VU1->EnableItem( 1, x86caps.hasStreamingSIMD2Extensions );
|
||||||
|
m_panel_VU1->EnableItem( 2, x86caps.hasStreamingSIMD2Extensions );
|
||||||
|
|
||||||
Pcsx2Config::RecompilerOptions& recOps( g_Conf->EmuOptions.Cpu.Recompiler );
|
Pcsx2Config::RecompilerOptions& recOps( g_Conf->EmuOptions.Cpu.Recompiler );
|
||||||
if( recOps.UseMicroVU0 )
|
if( recOps.UseMicroVU0 )
|
||||||
m_panel_VU0->SetSelection( recOps.EnableVU0 ? 1 : 0 );
|
m_panel_VU0->SetSelection( recOps.EnableVU0 ? 1 : 0 );
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
#include "App.h"
|
#include "App.h"
|
||||||
#include "Plugins.h"
|
#include "Plugins.h"
|
||||||
|
#include "SaveState.h"
|
||||||
#include "Utilities/ScopedPtr.h"
|
#include "Utilities/ScopedPtr.h"
|
||||||
#include "ConfigurationPanels.h"
|
#include "ConfigurationPanels.h"
|
||||||
#include "Dialogs/ModalPopups.h"
|
#include "Dialogs/ModalPopups.h"
|
||||||
|
@ -309,37 +310,43 @@ void Panels::PluginSelectorPanel::Apply()
|
||||||
break;
|
break;
|
||||||
} while( ++pi, pi->shortname != NULL );
|
} while( ++pi, pi->shortname != NULL );
|
||||||
|
|
||||||
|
bool isSuspended = false;
|
||||||
|
|
||||||
if( pi->shortname != NULL )
|
if( pi->shortname != NULL )
|
||||||
{
|
{
|
||||||
if( CoreThread.IsRunning() )
|
if( CoreThread.IsRunning() )
|
||||||
{
|
{
|
||||||
// [TODO] : Post notice that this shuts down existing emulation, and may not safely recover.
|
// [TODO] : Post notice that this shuts down existing emulation, and may not safely recover.
|
||||||
Dialogs::ExtensibleConfirmation dialog( this, ConfButtons().OK().Cancel(),
|
wxDialogWithHelpers dialog( this, _("Shutdown PS2 virtual machine?"), wxVERTICAL );
|
||||||
|
|
||||||
_("Shutdown PS2 virtual machine?"),
|
|
||||||
|
|
||||||
pxE( ".Popup:PluginSelector:ConfirmShutdown",
|
|
||||||
L"Warning! Changing plugins requires a complete shutdown and reset of the PS2 virtual machine. "
|
|
||||||
L"PCSX2 will attempt to save and restore the state, but if the newly selected plugins are "
|
|
||||||
L"incompatible the recovery may fail, and current progress will be lost."
|
|
||||||
L"\n\n"
|
|
||||||
L"Are you sure you want to apply settings now?"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
int result = Dialogs::IssueConfirmation( dialog, L"PluginSelector:ConfirmShutdown" );
|
dialog += dialog.Heading( pxE( ".Popup:PluginSelector:ConfirmShutdown",
|
||||||
|
L"Warning! Changing plugins requires a complete shutdown and reset of the PS2 virtual machine. "
|
||||||
|
L"PCSX2 will attempt to save and restore the state, but if the newly selected plugins are "
|
||||||
|
L"incompatible the recovery may fail, and current progress will be lost."
|
||||||
|
L"\n\n"
|
||||||
|
L"Are you sure you want to apply settings now?"
|
||||||
|
) );
|
||||||
|
|
||||||
|
int result = pxIssueConfirmation( dialog, MsgButtons().OK().Cancel(), L"PluginSelector:ConfirmShutdown" );
|
||||||
|
|
||||||
if( result == wxID_CANCEL )
|
if( result == wxID_CANCEL )
|
||||||
throw Exception::CannotApplySettings( this, "Cannot apply settings: canceled by user because plugins changed while the emulation state was active.", false );
|
throw Exception::CannotApplySettings( this, "Cannot apply settings: canceled by user because plugins changed while the emulation state was active.", false );
|
||||||
|
|
||||||
|
// FIXME : We only actually have to save plugins here, except the recovery code
|
||||||
|
// in SysCoreThread isn't quite set up yet to handle that (I think...) --air
|
||||||
|
|
||||||
|
isSuspended = CoreThread.Suspend();
|
||||||
|
StateCopy_FreezeToMem_Blocking();
|
||||||
}
|
}
|
||||||
|
|
||||||
sApp.SysReset();
|
// Don't use SysShutdown, it clears the StateCopy.
|
||||||
|
CoreThread.Cancel();
|
||||||
|
wxGetApp().m_CorePlugins = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !wxGetApp().m_CorePlugins )
|
if( !wxGetApp().m_CorePlugins )
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
LoadPluginsImmediate();
|
LoadPluginsImmediate();
|
||||||
}
|
}
|
||||||
catch( Exception::PluginError& ex )
|
catch( Exception::PluginError& ex )
|
||||||
|
@ -359,6 +366,8 @@ void Panels::PluginSelectorPanel::Apply()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( isSuspended ) CoreThread.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panels::PluginSelectorPanel::CancelRefresh()
|
void Panels::PluginSelectorPanel::CancelRefresh()
|
||||||
|
@ -591,6 +600,7 @@ void Panels::PluginSelectorPanel::EnumThread::ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
DevCon.WriteLn( "Plugin Enumeration Thread started..." );
|
DevCon.WriteLn( "Plugin Enumeration Thread started..." );
|
||||||
|
|
||||||
|
Sleep( 15 ); // give the window some time to paint.
|
||||||
YieldToMain();
|
YieldToMain();
|
||||||
|
|
||||||
for( int curidx=0; curidx < m_master.FileCount(); ++curidx )
|
for( int curidx=0; curidx < m_master.FileCount(); ++curidx )
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
RecentIsoManager::RecentIsoManager( wxMenu* menu )
|
RecentIsoManager::RecentIsoManager( wxMenu* menu )
|
||||||
: m_Menu( menu )
|
: m_Menu( menu )
|
||||||
, m_MaxLength( g_Conf->RecentFileCount )
|
, m_MaxLength( g_Conf->RecentIsoCount )
|
||||||
, m_Listener_SettingsLoadSave ( wxGetApp().Source_SettingsLoadSave(), EventListener<IniInterface>( this, OnSettingsLoadSave ) )
|
, m_Listener_SettingsLoadSave ( wxGetApp().Source_SettingsLoadSave(), EventListener<IniInterface>( this, OnSettingsLoadSave ) )
|
||||||
, m_Listener_SettingsApplied ( wxGetApp().Source_SettingsApplied(), EventListener<int>( this, OnSettingsApplied ) )
|
, m_Listener_SettingsApplied ( wxGetApp().Source_SettingsApplied(), EventListener<int>( this, OnSettingsApplied ) )
|
||||||
{
|
{
|
||||||
|
@ -166,7 +166,7 @@ void RecentIsoManager::DoSettingsLoadSave( IniInterface& ini )
|
||||||
{
|
{
|
||||||
RemoveAllFromMenu();
|
RemoveAllFromMenu();
|
||||||
|
|
||||||
m_MaxLength = g_Conf->RecentFileCount;
|
m_MaxLength = g_Conf->RecentIsoCount;
|
||||||
IniScopedGroup groupie( ini, L"RecentIso" );
|
IniScopedGroup groupie( ini, L"RecentIso" );
|
||||||
for( uint i=0; i<m_MaxLength; ++i )
|
for( uint i=0; i<m_MaxLength; ++i )
|
||||||
{
|
{
|
||||||
|
|
|
@ -141,7 +141,7 @@ const wxChar* __fastcall pxGetTranslation( const wxChar* message )
|
||||||
if( wxStrlen( message ) > 96 )
|
if( wxStrlen( message ) > 96 )
|
||||||
{
|
{
|
||||||
Console.Warning( "pxGetTranslation: Long message detected, maybe use pxE() instead?" );
|
Console.Warning( "pxGetTranslation: Long message detected, maybe use pxE() instead?" );
|
||||||
Console.Indent().WriteLn( Color_Green, L"Message: %s", message );
|
Console.WriteLn( Color_Green, L"Message: %s", message );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wxGetTranslation( message );
|
return wxGetTranslation( message );
|
||||||
|
|
|
@ -31,7 +31,6 @@ void __evt_fastcall pxLogTextCtrl::OnCoreThreadStatusChanged( void* obj, wxComma
|
||||||
|
|
||||||
if( mframe->HasWriteLock() ) return;
|
if( mframe->HasWriteLock() ) return;
|
||||||
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||||
mframe->m_win32_StupidRefreshTricks = 0;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +44,6 @@ void __evt_fastcall pxLogTextCtrl::OnCorePluginStatusChanged( void* obj, PluginE
|
||||||
|
|
||||||
if( mframe->HasWriteLock() ) return;
|
if( mframe->HasWriteLock() ) return;
|
||||||
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||||
mframe->m_win32_StupidRefreshTricks = 0;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +56,11 @@ pxLogTextCtrl::pxLogTextCtrl( wxWindow* parent )
|
||||||
, m_Listener_CorePluginStatus ( wxGetApp().Source_CorePluginStatus(), EventListener<PluginEventType> ( this, OnCorePluginStatusChanged ) )
|
, m_Listener_CorePluginStatus ( wxGetApp().Source_CorePluginStatus(), EventListener<PluginEventType> ( this, OnCorePluginStatusChanged ) )
|
||||||
{
|
{
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
m_win32_StupidRefreshTricks = 0;
|
m_win32_LinesPerScroll = 10;
|
||||||
m_win32_LinesPerScroll = 10;
|
m_win32_LinesPerPage = 0;
|
||||||
#endif
|
#endif
|
||||||
m_FreezeWrites = false;
|
m_IsPaused = false;
|
||||||
|
m_FreezeWrites = false;
|
||||||
|
|
||||||
Connect( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEventHandler(pxLogTextCtrl::OnThumbTrack) );
|
Connect( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEventHandler(pxLogTextCtrl::OnThumbTrack) );
|
||||||
Connect( wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEventHandler(pxLogTextCtrl::OnThumbRelease) );
|
Connect( wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEventHandler(pxLogTextCtrl::OnThumbRelease) );
|
||||||
|
@ -85,14 +84,12 @@ void pxLogTextCtrl::OnResize( wxSizeEvent& evt )
|
||||||
int fonty;
|
int fonty;
|
||||||
GetTextExtent( L"blaH yeah", NULL, &fonty );
|
GetTextExtent( L"blaH yeah", NULL, &fonty );
|
||||||
m_win32_LinesPerPage = (ctrly / fonty) + 1;
|
m_win32_LinesPerPage = (ctrly / fonty) + 1;
|
||||||
m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.25;
|
m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.40;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool m_IsPaused = false;
|
|
||||||
|
|
||||||
void pxLogTextCtrl::OnThumbTrack(wxScrollWinEvent& evt)
|
void pxLogTextCtrl::OnThumbTrack(wxScrollWinEvent& evt)
|
||||||
{
|
{
|
||||||
//Console.Warning( "Thumb Tracking!!!" );
|
//Console.Warning( "Thumb Tracking!!!" );
|
||||||
|
@ -131,16 +128,12 @@ void pxLogTextCtrl::ConcludeIssue( int lines )
|
||||||
// makes logging very slow, so we only send the message for status changes, so that the
|
// makes logging very slow, so we only send the message for status changes, so that the
|
||||||
// log aligns itself nicely when we pause emulation or when errors occur.
|
// log aligns itself nicely when we pause emulation or when errors occur.
|
||||||
|
|
||||||
//m_win32_StupidRefreshTricks += lines;
|
wxTextPos showpos = XYToPosition( 1, GetNumberOfLines()-m_win32_LinesPerScroll );
|
||||||
//if( m_win32_StupidRefreshTricks > m_win32_LinesPerScroll )
|
if( showpos > 0 )
|
||||||
{
|
ShowPosition( showpos );
|
||||||
wxTextPos showpos = XYToPosition( 1, GetNumberOfLines()-m_win32_LinesPerScroll );
|
|
||||||
if( showpos > 0 )
|
|
||||||
ShowPosition( showpos );
|
|
||||||
|
|
||||||
m_win32_StupidRefreshTricks = 0;
|
//::SendMessage((HWND)GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||||
//::SendMessage((HWND)GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1847,6 +1847,10 @@
|
||||||
RelativePath="..\..\gui\AdvancedDialog.h"
|
RelativePath="..\..\gui\AdvancedDialog.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\gui\Dialogs\AssertionDialog.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\gui\Dialogs\ConfigurationDialog.cpp"
|
RelativePath="..\..\gui\Dialogs\ConfigurationDialog.cpp"
|
||||||
>
|
>
|
||||||
|
|
|
@ -25,7 +25,8 @@ void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode
|
||||||
switch( errcode )
|
switch( errcode )
|
||||||
{
|
{
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
throw Exception::InvalidArgument( "Invalid argument" );
|
pxFailDev( L"Invalid argument" );
|
||||||
|
throw Exception::Stream( streamname, "Invalid argument" );
|
||||||
|
|
||||||
case EACCES: // Access denied!
|
case EACCES: // Access denied!
|
||||||
throw Exception::AccessDenied( streamname );
|
throw Exception::AccessDenied( streamname );
|
||||||
|
@ -75,7 +76,7 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
|
||||||
throw Exception::AccessDenied( streamname );
|
throw Exception::AccessDenied( streamname );
|
||||||
|
|
||||||
case ERROR_INVALID_HANDLE:
|
case ERROR_INVALID_HANDLE:
|
||||||
throw Exception::InvalidOperation( "Stream object or handle is invalid" );
|
throw Exception::BadStream( streamname, "Stream object or handle is invalid" );
|
||||||
|
|
||||||
case ERROR_SHARING_VIOLATION:
|
case ERROR_SHARING_VIOLATION:
|
||||||
throw Exception::AccessDenied( streamname, "Sharing violation" );
|
throw Exception::AccessDenied( streamname, "Sharing violation" );
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void ExecuteTaskInThread()
|
void ExecuteTaskInThread()
|
||||||
{
|
{
|
||||||
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
|
::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
|
||||||
if( m_outpipe == INVALID_HANDLE_VALUE ) return;
|
if( m_outpipe == INVALID_HANDLE_VALUE ) return;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -112,7 +112,7 @@ protected:
|
||||||
if( !ReadFile(m_outpipe, s8_Buf, sizeof(s8_Buf)-1, &u32_Read, NULL) )
|
if( !ReadFile(m_outpipe, s8_Buf, sizeof(s8_Buf)-1, &u32_Read, NULL) )
|
||||||
{
|
{
|
||||||
DWORD result = GetLastError();
|
DWORD result = GetLastError();
|
||||||
if( result == ERROR_HANDLE_EOF ) break;
|
if( result == ERROR_HANDLE_EOF || result == ERROR_BROKEN_PIPE ) break;
|
||||||
if( result == ERROR_IO_PENDING )
|
if( result == ERROR_IO_PENDING )
|
||||||
{
|
{
|
||||||
Yield( 10 );
|
Yield( 10 );
|
||||||
|
@ -172,6 +172,10 @@ class WinPipeRedirection : public PipeRedirectionBase
|
||||||
DeclareNoncopyableObject( WinPipeRedirection );
|
DeclareNoncopyableObject( WinPipeRedirection );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
DWORD m_stdhandle;
|
||||||
|
FILE* m_stdfp;
|
||||||
|
FILE m_stdfp_copy;
|
||||||
|
|
||||||
HANDLE m_readpipe;
|
HANDLE m_readpipe;
|
||||||
HANDLE m_writepipe;
|
HANDLE m_writepipe;
|
||||||
int m_crtFile;
|
int m_crtFile;
|
||||||
|
@ -187,21 +191,25 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
||||||
: m_readpipe(INVALID_HANDLE_VALUE)
|
: m_Thread( m_readpipe, (stdstream == stderr) ? Color_Red : Color_Black )
|
||||||
, m_writepipe(INVALID_HANDLE_VALUE)
|
|
||||||
, m_crtFile(-1)
|
|
||||||
, m_fp(NULL)
|
|
||||||
, m_Thread( m_readpipe, (stdstream == stderr) ? Color_Red : Color_Black )
|
|
||||||
{
|
{
|
||||||
|
m_stdhandle = ( stdstream == stderr ) ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE;
|
||||||
|
m_stdfp = stdstream;
|
||||||
|
m_stdfp_copy = *stdstream;
|
||||||
|
|
||||||
|
m_readpipe = INVALID_HANDLE_VALUE;
|
||||||
|
m_writepipe = INVALID_HANDLE_VALUE;
|
||||||
|
m_crtFile = -1;
|
||||||
|
m_fp = NULL;
|
||||||
|
|
||||||
|
pxAssume( (stdstream == stderr) || (stdstream == stdout) );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pxAssert( (stdstream == stderr) || (stdstream == stdout) );
|
|
||||||
DWORD stdhandle = ( stdstream == stderr ) ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE;
|
|
||||||
|
|
||||||
if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) )
|
if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) )
|
||||||
throw Exception::Win32Error( "CreatePipe failed." );
|
throw Exception::Win32Error( "CreatePipe failed." );
|
||||||
|
|
||||||
if( 0 == SetStdHandle( stdhandle, m_writepipe ) )
|
if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) )
|
||||||
throw Exception::Win32Error( "SetStdHandle failed." );
|
throw Exception::Win32Error( "SetStdHandle failed." );
|
||||||
|
|
||||||
// Note: Don't use GetStdHandle to "confirm" the handle.
|
// Note: Don't use GetStdHandle to "confirm" the handle.
|
||||||
|
@ -222,11 +230,19 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
||||||
if( m_fp == NULL )
|
if( m_fp == NULL )
|
||||||
throw Exception::RuntimeError( "_fdopen returned NULL." );
|
throw Exception::RuntimeError( "_fdopen returned NULL." );
|
||||||
|
|
||||||
*stdstream = *m_fp;
|
*m_stdfp = *m_fp; // omg hack. but it works >_<
|
||||||
setvbuf( stdstream, NULL, _IONBF, 0 );
|
setvbuf( stdstream, NULL, _IONBF, 0 );
|
||||||
|
|
||||||
m_Thread.Start();
|
m_Thread.Start();
|
||||||
}
|
}
|
||||||
|
catch( Exception::BaseThreadError& ex )
|
||||||
|
{
|
||||||
|
// thread object will become invalid because of scoping after we leave
|
||||||
|
// the constructor, so re-pack a new exception:
|
||||||
|
|
||||||
|
Cleanup();
|
||||||
|
throw Exception::RuntimeError( ex.FormatDiagnosticMessage(), ex.FormatDisplayMessage() );
|
||||||
|
}
|
||||||
catch( Exception::BaseException& ex )
|
catch( Exception::BaseException& ex )
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
|
@ -235,6 +251,9 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
||||||
}
|
}
|
||||||
catch( ... )
|
catch( ... )
|
||||||
{
|
{
|
||||||
|
// C++ doesn't execute the object destructor automatically, because it's fail++
|
||||||
|
// (and I'm *not* encapsulating each handle into its own object >_<)
|
||||||
|
|
||||||
Cleanup();
|
Cleanup();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -247,6 +266,12 @@ WinPipeRedirection::~WinPipeRedirection()
|
||||||
|
|
||||||
void WinPipeRedirection::Cleanup() throw()
|
void WinPipeRedirection::Cleanup() throw()
|
||||||
{
|
{
|
||||||
|
// restore the old handle we so graciously hacked earlier ;)
|
||||||
|
// (or don't and suffer CRT crashes! ahaha!)
|
||||||
|
|
||||||
|
if( m_stdfp != NULL )
|
||||||
|
*m_stdfp = m_stdfp_copy;
|
||||||
|
|
||||||
// Cleanup Order Notes:
|
// Cleanup Order Notes:
|
||||||
// * The redirection thread is most likely blocking on ReadFile(), so we can't Cancel yet, lest we deadlock --
|
// * The redirection thread is most likely blocking on ReadFile(), so we can't Cancel yet, lest we deadlock --
|
||||||
// Closing the writepipe (either directly or through the fp/crt handles) issues an EOF to the thread,
|
// Closing the writepipe (either directly or through the fp/crt handles) issues an EOF to the thread,
|
||||||
|
|
|
@ -495,31 +495,44 @@ static const uint m_recBlockAllocSize =
|
||||||
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK))
|
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK))
|
||||||
+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::Base;
|
+ RECCONSTBUF_SIZE * sizeof(u32) + Ps2MemSize::Base;
|
||||||
|
|
||||||
|
static void recThrowHardwareDeficiency( const wxChar* extFail )
|
||||||
|
{
|
||||||
|
throw Exception::HardwareDeficiency(
|
||||||
|
wxsFormat( L"R5900-32 recompiler init failed: %s is not available.", extFail),
|
||||||
|
wxsFormat(_("%s Extensions not found. The R5900-32 recompiler requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static void recAlloc()
|
static void recAlloc()
|
||||||
{
|
{
|
||||||
// Hardware Requirements Check...
|
// Hardware Requirements Check...
|
||||||
|
|
||||||
if ( !( x86caps.hasMultimediaExtensions ) )
|
if ( !x86caps.hasMultimediaExtensions )
|
||||||
throw Exception::HardwareDeficiency( "Processor doesn't support MMX" );
|
recThrowHardwareDeficiency( L"MMX" );
|
||||||
|
|
||||||
if ( !( x86caps.hasStreamingSIMDExtensions ) )
|
if ( !x86caps.hasStreamingSIMDExtensions )
|
||||||
throw Exception::HardwareDeficiency( "Processor doesn't support SSE" );
|
recThrowHardwareDeficiency( L"SSE" );
|
||||||
|
|
||||||
if ( !( x86caps.hasStreamingSIMD2Extensions ) )
|
if ( !x86caps.hasStreamingSIMD2Extensions )
|
||||||
throw Exception::HardwareDeficiency( "Processor doesn't support SSE2" );
|
recThrowHardwareDeficiency( L"SSE2" );
|
||||||
|
|
||||||
if( recMem == NULL )
|
if( recMem == NULL )
|
||||||
{
|
{
|
||||||
// Note: the VUrec depends on being able to grab an allocation below the 0x10000000 line,
|
// It's handy to have a constant base address for the EE recompiler buffer, since it
|
||||||
// so we give the EErec an address above that to try first as it's basemem address, hence
|
// allows me to key in the address directly in the debugger, and also recognize EE
|
||||||
// the 0x20000000 pick.
|
// recompiled code from user-provisioned stack traces. But besides those, the recompiler
|
||||||
|
// has no actual restrictions on where it's compiled code buffer is located.
|
||||||
|
|
||||||
|
// Note: the SuperVU recompiler depends on being able to grab an allocation below the
|
||||||
|
// 0x10000000 line, so we give the EErec an address above that to try first as it's
|
||||||
|
// basemem address, hence the 0x20000000 pick.
|
||||||
|
|
||||||
const uint cachememsize = REC_CACHEMEM+0x1000;
|
const uint cachememsize = REC_CACHEMEM+0x1000;
|
||||||
recMem = (u8*)SysMmapEx( 0x20000000, cachememsize, 0, "recAlloc(R5900)" );
|
recMem = (u8*)SysMmapEx( 0x20000000, cachememsize, 0, "recAlloc(R5900)" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( recMem == NULL )
|
if( recMem == NULL )
|
||||||
throw Exception::OutOfMemory( "R5900-32 > failed to allocate recompiler memory." );
|
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating recompiled code buffer." );
|
||||||
|
|
||||||
// Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory.
|
// Goal: Allocate BASEBLOCKs for every possible branch target in PS2 memory.
|
||||||
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
// Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are
|
||||||
|
@ -529,14 +542,14 @@ static void recAlloc()
|
||||||
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
|
m_recBlockAlloc = (u8*) _aligned_malloc( m_recBlockAllocSize, 4096 );
|
||||||
|
|
||||||
if( m_recBlockAlloc == NULL )
|
if( m_recBlockAlloc == NULL )
|
||||||
throw Exception::OutOfMemory( "R5900-32 Init > Failed to allocate memory for BASEBLOCK tables." );
|
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating BASEBLOCK tables." );
|
||||||
|
|
||||||
u8* curpos = m_recBlockAlloc;
|
u8* curpos = m_recBlockAlloc;
|
||||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
|
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
|
||||||
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
|
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
|
||||||
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
|
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
|
||||||
recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32);
|
recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32);
|
||||||
recRAMCopy = (u32*)curpos;
|
recRAMCopy = (u32*)curpos;
|
||||||
|
|
||||||
if( s_pInstCache == NULL )
|
if( s_pInstCache == NULL )
|
||||||
{
|
{
|
||||||
|
@ -545,7 +558,7 @@ static void recAlloc()
|
||||||
}
|
}
|
||||||
|
|
||||||
if( s_pInstCache == NULL )
|
if( s_pInstCache == NULL )
|
||||||
throw Exception::OutOfMemory( "R5900-32 Init > failed to allocate memory for pInstCache." );
|
throw Exception::OutOfMemory( "R5900-32: Out of memory allocating InstCache." );
|
||||||
|
|
||||||
// No errors.. Proceed with initialization:
|
// No errors.. Proceed with initialization:
|
||||||
|
|
||||||
|
@ -564,11 +577,13 @@ struct ManualPageTracking
|
||||||
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
|
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
|
||||||
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
|
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
|
||||||
|
|
||||||
static bool eeRecIsReset = false;
|
static u32 eeRecIsReset = 0;
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
void recResetEE( void )
|
void recResetEE( void )
|
||||||
{
|
{
|
||||||
|
if( AtomicExchange( eeRecIsReset, true ) ) return;
|
||||||
|
|
||||||
Console.WriteLn( Color_StrongBlack, "Issuing EE/iR5900-32 Recompiler Reset" );
|
Console.WriteLn( Color_StrongBlack, "Issuing EE/iR5900-32 Recompiler Reset" );
|
||||||
|
|
||||||
maxrecmem = 0;
|
maxrecmem = 0;
|
||||||
|
@ -630,7 +645,6 @@ void recResetEE( void )
|
||||||
x86FpuState = FPU_STATE;
|
x86FpuState = FPU_STATE;
|
||||||
|
|
||||||
branch = 0;
|
branch = 0;
|
||||||
eeRecIsReset = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recShutdown( void )
|
static void recShutdown( void )
|
||||||
|
@ -656,26 +670,21 @@ static jmp_buf m_SetJmp_StateCheck;
|
||||||
|
|
||||||
static void recCheckExecutionState()
|
static void recCheckExecutionState()
|
||||||
{
|
{
|
||||||
#if PCSX2_SEH
|
|
||||||
SysCoreThread::Get().StateCheckInThread();
|
|
||||||
|
|
||||||
if( eeRecIsReset )
|
|
||||||
throw Exception::ForceDispatcherReg();
|
|
||||||
#else
|
|
||||||
|
|
||||||
// Without SEH we'll need to hop to a safehouse point outside the scope of recompiled
|
|
||||||
// code. C++ exceptions can't cross the mighty chasm in the stackframe that the recompiler
|
|
||||||
// creates. However, the longjump is slow so we only want to do one when absolutely
|
|
||||||
// necessary:
|
|
||||||
|
|
||||||
pxAssert( !eeRecIsReset ); // should only be changed during suspended thread states
|
pxAssert( !eeRecIsReset ); // should only be changed during suspended thread states
|
||||||
|
|
||||||
if( SysCoreThread::Get().HasPendingStateChangeRequest() )
|
if( GetCoreThread().HasPendingStateChangeRequest() )
|
||||||
{
|
{
|
||||||
longjmp( m_SetJmp_StateCheck, SetJmp_Dispatcher );
|
#if PCSX2_SEH
|
||||||
}
|
throw Exception::ForceDispatcherReg();
|
||||||
|
#else
|
||||||
|
// Without SEH we'll need to hop to a safehouse point outside the scope of recompiled
|
||||||
|
// code. C++ exceptions can't cross the mighty chasm in the stackframe that the recompiler
|
||||||
|
// creates. However, the longjump is slow so we only want to do one when absolutely
|
||||||
|
// necessary:
|
||||||
|
|
||||||
|
longjmp( m_SetJmp_StateCheck, 1 );
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recExecute()
|
static void recExecute()
|
||||||
|
@ -684,64 +693,36 @@ static void recExecute()
|
||||||
// [TODO] fix this comment to explain various code entry/exit points, when I'm not so tired!
|
// [TODO] fix this comment to explain various code entry/exit points, when I'm not so tired!
|
||||||
|
|
||||||
#if PCSX2_SEH
|
#if PCSX2_SEH
|
||||||
try {
|
eeRecIsReset = false;
|
||||||
while( true )
|
g_EEFreezeRegs = true;
|
||||||
{
|
|
||||||
eeRecIsReset = false;
|
|
||||||
g_EEFreezeRegs = true;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
EnterRecompiledCode();
|
EnterRecompiledCode();
|
||||||
}
|
|
||||||
catch( Exception::ForceDispatcherReg& ) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch( Exception::ExitRecExecute& ) {}
|
catch( Exception::ForceDispatcherReg& ) { }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
switch( setjmp( m_SetJmp_StateCheck ) )
|
int oldstate;
|
||||||
|
|
||||||
|
if( !setjmp( m_SetJmp_StateCheck ) )
|
||||||
{
|
{
|
||||||
case 0: // first run, fall through to Dispatcher
|
eeRecIsReset = false;
|
||||||
case SetJmp_Dispatcher:
|
g_EEFreezeRegs = true;
|
||||||
while( true )
|
|
||||||
{
|
|
||||||
int oldstate;
|
|
||||||
|
|
||||||
// Important! Most of the console logging and such has cancel points in it. This is great
|
// Important! Most of the console logging and such has cancel points in it. This is great
|
||||||
// in Windows, where SEH lets us safely kill a thread from anywhere we want. This is bad
|
// in Windows, where SEH lets us safely kill a thread from anywhere we want. This is bad
|
||||||
// in Linux, which cannot have a C++ exception cross the recompiler. Hence the changing
|
// in Linux, which cannot have a C++ exception cross the recompiler. Hence the changing
|
||||||
// of the cancelstate here!
|
// of the cancelstate here!
|
||||||
|
|
||||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
||||||
SysCoreThread::Get().StateCheckInThread();
|
EnterRecompiledCode();
|
||||||
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
|
||||||
|
// Generally unreachable code here ...
|
||||||
eeRecIsReset = false;
|
}
|
||||||
|
else
|
||||||
#ifdef _WIN32
|
{
|
||||||
__try {
|
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
||||||
#endif
|
|
||||||
|
|
||||||
EnterRecompiledCode();
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
} __finally
|
|
||||||
{
|
|
||||||
// This assertion is designed to help me troubleshoot the setjmp behavior from Win32.
|
|
||||||
// If the recompiler throws an unhandled SEH exception with SEH support disabled (which
|
|
||||||
// is typically a pthread_cancel) then this will fire and let me know.
|
|
||||||
|
|
||||||
// FIXME: Doesn't work because SEH is remarkably clever and executes the _finally block
|
|
||||||
// even when I use longjmp to restart the loop. Maybe a workaround exists? :/
|
|
||||||
|
|
||||||
//pxFailDev( "Recompiler threw an SEH exception with SEH disabled; possibly due to pthread_cancel." );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SetJmp_Exit: break;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -858,7 +839,7 @@ static void recExitExecution()
|
||||||
#if PCSX2_SEH
|
#if PCSX2_SEH
|
||||||
throw Exception::ExitRecExecute();
|
throw Exception::ExitRecExecute();
|
||||||
#else
|
#else
|
||||||
longjmp( m_SetJmp_StateCheck, SetJmp_Exit );
|
longjmp( m_SetJmp_StateCheck, 1 );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1319,7 +1300,7 @@ static void __fastcall recRecompile( const u32 startpc )
|
||||||
if (dumplog & 4) iDumpRegisters(startpc, 0);
|
if (dumplog & 4) iDumpRegisters(startpc, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pxAssert( startpc );
|
pxAssume( startpc );
|
||||||
|
|
||||||
// if recPtr reached the mem limit reset whole mem
|
// if recPtr reached the mem limit reset whole mem
|
||||||
if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) {
|
if ( ( (uptr)recPtr - (uptr)recMem ) >= REC_CACHEMEM-0x40000 || dumplog == 0xffffffff) {
|
||||||
|
@ -1348,7 +1329,7 @@ static void __fastcall recRecompile( const u32 startpc )
|
||||||
|
|
||||||
s_pCurBlockEx = recBlocks.New(HWADDR(startpc), (uptr)recPtr);
|
s_pCurBlockEx = recBlocks.New(HWADDR(startpc), (uptr)recPtr);
|
||||||
|
|
||||||
pxAssert(s_pCurBlockEx);
|
pxAssume(s_pCurBlockEx);
|
||||||
|
|
||||||
branch = 0;
|
branch = 0;
|
||||||
|
|
||||||
|
@ -1359,7 +1340,7 @@ static void __fastcall recRecompile( const u32 startpc )
|
||||||
g_cpuHasConstReg = g_cpuFlushedConstReg = 1;
|
g_cpuHasConstReg = g_cpuFlushedConstReg = 1;
|
||||||
g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff;
|
g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff;
|
||||||
g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0;
|
g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0;
|
||||||
pxAssert( g_cpuConstRegs[0].UD[0] == 0 );
|
pxAssume( g_cpuConstRegs[0].UD[0] == 0 );
|
||||||
|
|
||||||
_initX86regs();
|
_initX86regs();
|
||||||
_initXMMregs();
|
_initXMMregs();
|
||||||
|
|
|
@ -67,20 +67,20 @@ const __aligned(32) mVU_Globals mVUglob = {
|
||||||
// Micro VU - Main Functions
|
// Micro VU - Main Functions
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
microVUt(void) mVUthrowHardwareDeficiency( const wxChar* extFail )
|
microVUt(void) mVUthrowHardwareDeficiency( const wxChar* extFail, int vuIndex )
|
||||||
{
|
{
|
||||||
throw Exception::HardwareDeficiency(
|
throw Exception::HardwareDeficiency(
|
||||||
L"microVU init error: SSE1 is not available!",
|
wxsFormat( L"microVU%d recompiler init failed: %s is not available.", vuIndex, extFail),
|
||||||
wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), L"SSE" )
|
wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), extFail )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only run this once per VU! ;)
|
// Only run this once per VU! ;)
|
||||||
microVUt(void) mVUinit(VURegs* vuRegsPtr, int vuIndex) {
|
microVUt(void) mVUinit(VURegs* vuRegsPtr, int vuIndex) {
|
||||||
|
|
||||||
if(!x86caps.hasMultimediaExtensions) mVUthrowHardwareDeficiency( L"MMX" );
|
if(!x86caps.hasMultimediaExtensions) mVUthrowHardwareDeficiency( L"MMX", vuIndex );
|
||||||
if(!x86caps.hasStreamingSIMDExtensions) mVUthrowHardwareDeficiency( L"SSE" );
|
if(!x86caps.hasStreamingSIMDExtensions) mVUthrowHardwareDeficiency( L"SSE", vuIndex );
|
||||||
if(!x86caps.hasStreamingSIMD2Extensions) mVUthrowHardwareDeficiency( L"SSE2" );
|
if(!x86caps.hasStreamingSIMD2Extensions) mVUthrowHardwareDeficiency( L"SSE2", vuIndex );
|
||||||
|
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
memset(&mVU->prog, 0, sizeof(mVU->prog));
|
memset(&mVU->prog, 0, sizeof(mVU->prog));
|
||||||
|
@ -182,17 +182,19 @@ microVUt(void) mVUclear(mV, u32 addr, u32 size) {
|
||||||
// Clears program data
|
// Clears program data
|
||||||
microVUf(void) mVUclearProg(int progIndex) {
|
microVUf(void) mVUclearProg(int progIndex) {
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
mVUprogI.used = 0;
|
microProgram& program = mVU->prog.prog[progIndex];
|
||||||
mVUprogI.isDead = 1;
|
|
||||||
mVUprogI.isOld = 1;
|
program.used = 0;
|
||||||
mVUprogI.frame = mVU->prog.curFrame;
|
program.isDead = 1;
|
||||||
for (int j = 0; j <= mVUprogI.ranges.max; j++) {
|
program.isOld = 1;
|
||||||
mVUprogI.ranges.range[j][0] = -1; // Set range to
|
program.frame = mVU->prog.curFrame;
|
||||||
mVUprogI.ranges.range[j][1] = -1; // indeterminable status
|
for (int j = 0; j <= program.ranges.max; j++) {
|
||||||
mVUprogI.ranges.total = -1;
|
program.ranges.range[j][0] = -1; // Set range to
|
||||||
|
program.ranges.range[j][1] = -1; // indeterminable status
|
||||||
|
program.ranges.total = -1;
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
|
for (u32 i = 0; i < (mVU->progSize / 2); i++) {
|
||||||
safe_delete(mVUprogI.block[i]);
|
safe_delete(program.block[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,6 +324,9 @@ microVUf(int) mVUsearchProg() {
|
||||||
return 1; // If !cleared, then we're still on the same program as last-time ;)
|
return 1; // If !cleared, then we're still on the same program as last-time ;)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 mvu0_allocated = 0;
|
||||||
|
static u32 mvu1_allocated = 0;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// recMicroVU0
|
// recMicroVU0
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
@ -331,13 +336,21 @@ recMicroVU0::recMicroVU0() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU0::Allocate() {
|
void recMicroVU0::Allocate() {
|
||||||
if( AtomicIncrement( m_AllocCount ) == 0 )
|
if( m_AllocCount == 0 )
|
||||||
mVUinit( &VU0, 0 );
|
{
|
||||||
|
++m_AllocCount;
|
||||||
|
if( AtomicExchange( mvu0_allocated, 1 ) == 0 )
|
||||||
|
mVUinit( &VU0, 0 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU0::Shutdown() throw() {
|
void recMicroVU0::Shutdown() throw() {
|
||||||
if( AtomicDecrement( m_AllocCount ) == 0 )
|
if( m_AllocCount > 0 )
|
||||||
mVUclose(µVU0);
|
{
|
||||||
|
--m_AllocCount;
|
||||||
|
if( AtomicExchange( mvu0_allocated, 0 ) == 1 )
|
||||||
|
mVUclose(µVU0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU0::Reset() {
|
void recMicroVU0::Reset() {
|
||||||
|
@ -356,7 +369,7 @@ void recMicroVU0::ExecuteBlock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU0::Clear(u32 addr, u32 size) {
|
void recMicroVU0::Clear(u32 addr, u32 size) {
|
||||||
pxAssert( m_AllocCount ); // please allocate me first! :|
|
pxAssert( mvu0_allocated ); // please allocate me first! :|
|
||||||
mVUclear(µVU0, addr, size);
|
mVUclear(µVU0, addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,32 +380,35 @@ void recMicroVU0::Vsync() throw() {
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
// recMicroVU1
|
// recMicroVU1
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
recMicroVU1::recMicroVU1()
|
recMicroVU1::recMicroVU1() {
|
||||||
{
|
|
||||||
IsInterpreter = false;
|
IsInterpreter = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU1::Allocate()
|
void recMicroVU1::Allocate() {
|
||||||
{
|
if( m_AllocCount == 0 )
|
||||||
if( AtomicIncrement( m_AllocCount ) == 0 )
|
{
|
||||||
mVUinit( &VU1, 1 );
|
++m_AllocCount;
|
||||||
|
if( AtomicExchange( mvu1_allocated, 1 ) == 0 )
|
||||||
|
mVUinit( &VU1, 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU1::Shutdown() throw()
|
void recMicroVU1::Shutdown() throw() {
|
||||||
{
|
if( m_AllocCount > 0 )
|
||||||
if( AtomicDecrement( m_AllocCount ) == 0 )
|
{
|
||||||
mVUclose(µVU1);
|
--m_AllocCount;
|
||||||
|
if( AtomicExchange( mvu1_allocated, 0 ) == 1 )
|
||||||
|
mVUclose(µVU1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU1::Reset()
|
void recMicroVU1::Reset() {
|
||||||
{
|
|
||||||
if( !pxAssertDev( m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!" ) ) return;
|
if( !pxAssertDev( m_AllocCount, "MicroVU1 CPU Provider has not been allocated prior to reset!" ) ) return;
|
||||||
mVUreset(µVU1);
|
mVUreset(µVU1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU1::ExecuteBlock()
|
void recMicroVU1::ExecuteBlock() {
|
||||||
{
|
pxAssert( mvu1_allocated ); // please allocate me first! :|
|
||||||
pxAssert( m_AllocCount ); // please allocate me first! :|
|
|
||||||
|
|
||||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0) return;
|
if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0) return;
|
||||||
pxAssert( (VU1.VI[REG_TPC].UL&7) == 0 );
|
pxAssert( (VU1.VI[REG_TPC].UL&7) == 0 );
|
||||||
|
@ -402,8 +418,7 @@ void recMicroVU1::ExecuteBlock()
|
||||||
XMMRegisters::Thaw();
|
XMMRegisters::Thaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void recMicroVU1::Clear(u32 addr, u32 size)
|
void recMicroVU1::Clear(u32 addr, u32 size) {
|
||||||
{
|
|
||||||
pxAssert( m_AllocCount ); // please allocate me first! :|
|
pxAssert( m_AllocCount ); // please allocate me first! :|
|
||||||
mVUclear(µVU1, addr, size);
|
mVUclear(µVU1, addr, size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,8 +121,8 @@ extern const __aligned(32) mVU_Globals mVUglob;
|
||||||
// Function/Template Stuff
|
// Function/Template Stuff
|
||||||
#define mVUx (vuIndex ? µVU1 : µVU0)
|
#define mVUx (vuIndex ? µVU1 : µVU0)
|
||||||
#define mVUop(opName) static void opName (mP)
|
#define mVUop(opName) static void opName (mP)
|
||||||
#define microVUr(aType) __recInline aType
|
#define microVUr(aType) static __recInline aType
|
||||||
#define microVUt(aType) __forceinline aType
|
#define microVUt(aType) static __forceinline aType
|
||||||
#define microVUx(aType) template<int vuIndex> aType
|
#define microVUx(aType) template<int vuIndex> aType
|
||||||
#define microVUf(aType) template<int vuIndex> __forceinline aType
|
#define microVUf(aType) template<int vuIndex> __forceinline aType
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue