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
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
# define pxDebugCode(code) code
|
||||
#else
|
||||
# define pxDebugCode(code)
|
||||
#endif
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// __aligned / __aligned16 / __pagealigned
|
||||
//
|
||||
|
@ -201,8 +208,8 @@ static const int __pagesize = PCSX2_PAGESIZE;
|
|||
// Don't know if there are Visual C++ equivalents of these.
|
||||
# define __hot
|
||||
# define __cold
|
||||
# define likely(x) x
|
||||
# define unlikely(x) x
|
||||
# define likely(x) (!!(x))
|
||||
# define unlikely(x) (!!(x))
|
||||
|
||||
# define CALLBACK __stdcall
|
||||
|
||||
|
|
|
@ -15,60 +15,136 @@
|
|||
|
||||
#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
|
||||
// return the result of the specified conditional; useful for handling failed assertions in
|
||||
// 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
|
||||
// builds. If using assertions as part of a conditional, the conditional code *will* not
|
||||
// be optimized out, so use conditionals with caution.
|
||||
// All macros return TRUE if the assertion succeeds, or FALSE if the assertion failed
|
||||
// (thus matching the condition of the assertion itself).
|
||||
//
|
||||
// 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
|
||||
// use is for checking thread affinity on utility functions.
|
||||
//
|
||||
// Credits Notes: These macros are based on a combination of wxASSERT, MSVCRT's assert
|
||||
// and the ATL's Assertion/Assumption macros. the best of all worlds!
|
||||
// Credits: These macros are based on a combination of wxASSERT, MSVCRT's assert and the
|
||||
// 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)
|
||||
|
||||
# define pxAssertMsg(cond, msg) ( (!!(cond)) || \
|
||||
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), likely(cond)) )
|
||||
# define pxAssertMsg(cond, msg) pxAssertRel(cond, msg)
|
||||
# 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 pxFailDev(msg) pxAssertDev(false, msg)
|
||||
# define pxFail(msg) pxAssumeMsg(false, msg)
|
||||
# define pxFailDev(msg) pxAssumeDev(false, msg)
|
||||
|
||||
#elif defined(PCSX2_DEVBUILD)
|
||||
|
||||
// Devel builds use __assume for standard assertions and call pxOnAssertDevel
|
||||
// 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)) || \
|
||||
(pxOnAssert(__TFILE__, __LINE__, __WXFUNCTION__, _T(#cond), msg), likely(cond)) )
|
||||
# define pxAssume(cond) (__assume(cond))
|
||||
# define pxAssumeDev(cond, msg) pxAssumeMsg(cond, msg)
|
||||
|
||||
# define pxFail(msg) (__assume(false), false)
|
||||
# define pxFailDev(msg ) pxAssertDev(false, msg)
|
||||
# define pxFail(msg) (__assume(false))
|
||||
# define pxFailDev(msg) pxAssumeDev(false, msg)
|
||||
|
||||
#else
|
||||
|
||||
// Release Builds just use __assume as an optimization, and return the conditional
|
||||
// as a result (which is optimized to nil if unused).
|
||||
|
||||
# define pxAssertMsg(cond, msg) (__assume(cond), likely(cond))
|
||||
# define pxAssertDev(cond, msg) (__assume(cond), likely(cond))
|
||||
# define pxFail(msg) (__assume(false), false)
|
||||
# define pxFailDev(msg) (__assume(false), false)
|
||||
# define pxAssertMsg(cond, msg) (likely(cond))
|
||||
# define pxAssertDev(cond, msg) (likely(cond))
|
||||
|
||||
# define pxAssume(cond) (__assume(cond))
|
||||
# define pxAssumeDev(cond, msg) (__assume(cond))
|
||||
|
||||
# define pxFail(msg) (__assume(false))
|
||||
# define pxFailDev(msg) (__assume(false))
|
||||
|
||||
#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.
|
||||
// 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) ) )
|
||||
|
||||
|
||||
extern void pxOnAssert( const wxChar* file, int line, const char* func, const wxChar* cond, const wxChar* msg);
|
||||
extern void pxOnAssert( const wxChar* file, int line, const char* func, const wxChar* cond, const char* msg);
|
||||
extern void pxOnAssert( const DiagnosticOrigin& origin, const wxChar* msg=NULL );
|
||||
extern void pxOnAssert( const DiagnosticOrigin& origin, const char* msg );
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
// that it will not generate any code, LUTs, or conditionals to handle it.
|
||||
//
|
||||
// * In debug 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).
|
||||
// * In debug/devel builds the default case will cause an assertion.
|
||||
//
|
||||
#ifndef jNO_DEFAULT
|
||||
|
||||
#if defined(__cplusplus) && defined(PCSX2_DEVBUILD)
|
||||
# define jNO_DEFAULT \
|
||||
default: \
|
||||
{ \
|
||||
pxFailDev( "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)" ); \
|
||||
break; \
|
||||
}
|
||||
default: \
|
||||
{ \
|
||||
pxFailDev( "Incorrect usage of jNO_DEFAULT detected (default case is not unreachable!)" ); \
|
||||
break; \
|
||||
}
|
||||
#else
|
||||
# define jNO_DEFAULT \
|
||||
default: \
|
||||
{ \
|
||||
jASSUME(0); \
|
||||
break; \
|
||||
}
|
||||
default: \
|
||||
{ \
|
||||
jASSUME(0); \
|
||||
break; \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -38,11 +38,7 @@
|
|||
Console.Error( ex.what() ); \
|
||||
}
|
||||
|
||||
#ifdef __GNUG__
|
||||
# define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL( __PRETTY_FUNCTION__ )
|
||||
#else
|
||||
# define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL( __FUNCTION__ )
|
||||
#endif
|
||||
#define DESTRUCTOR_CATCHALL __DESTRUCTOR_CATCHALL( __pxFUNCTION__ )
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
|
@ -56,7 +52,7 @@ namespace Exception
|
|||
// 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.
|
||||
// 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,
|
||||
// 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 ); }
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// RuntimeError / LogicError - Generalized Exceptions
|
||||
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
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.") )
|
||||
};
|
||||
|
||||
// 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
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -227,24 +215,6 @@ namespace Exception
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -32,6 +32,9 @@ class wxTimeSpan;
|
|||
namespace Threading
|
||||
{
|
||||
class PersistentThread;
|
||||
|
||||
PersistentThread* pxGetCurrentThread();
|
||||
wxString pxGetCurrentThreadName();
|
||||
}
|
||||
|
||||
namespace Exception
|
||||
|
@ -346,12 +349,11 @@ namespace Threading
|
|||
DeclareNoncopyableObject(PersistentThread);
|
||||
|
||||
protected:
|
||||
typedef int (*PlainJoeFP)();
|
||||
|
||||
wxString m_name; // diagnostic name for our 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
|
||||
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 Cancel( bool isBlocking = true );
|
||||
virtual bool Cancel( const wxTimeSpan& timeout );
|
||||
virtual bool Detach();
|
||||
virtual void Block();
|
||||
virtual void RethrowException() const;
|
||||
|
@ -419,12 +422,13 @@ namespace Threading
|
|||
|
||||
void FrankenMutex( Mutex& mutex );
|
||||
|
||||
bool AffinityAssert_AllowFromSelf() const;
|
||||
bool AffinityAssert_DisallowFromSelf() const;
|
||||
bool AffinityAssert_AllowFromSelf( const DiagnosticOrigin& origin ) const;
|
||||
bool AffinityAssert_DisallowFromSelf( const DiagnosticOrigin& origin ) const;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Section of methods for internal use only.
|
||||
|
||||
bool _basecancel();
|
||||
void _selfRunningTest( const wxChar* name ) const;
|
||||
void _DoSetThreadName( const wxString& 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 );
|
||||
|
||||
template<>
|
||||
inline void operator+=( wxSizer& target, const pxWindowAndFlags<pxCheckBox>& src )
|
||||
{
|
||||
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& SetSelection( int idx );
|
||||
pxRadioPanel& SetDefault( int idx );
|
||||
pxRadioPanel& SetDefaultItem( int idx );
|
||||
pxRadioPanel& EnableItem( int idx, bool enable=true );
|
||||
|
||||
int GetSelection() 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 );
|
||||
|
||||
template<>
|
||||
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 );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void operator+=( wxSizer* target, const pxWindowAndFlags<pxStaticText>& src )
|
||||
{
|
||||
src.window->AddTo( target, src.flags );
|
||||
//target.Add( src.window, src.flags );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxStaticHeading
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -52,15 +52,25 @@ struct pxAlignmentType
|
|||
|
||||
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
|
||||
{
|
||||
return Apply();
|
||||
}
|
||||
|
||||
wxSizerFlags operator | ( const wxSizerFlags& _flgs )
|
||||
{
|
||||
return Apply( _flgs );
|
||||
}
|
||||
};
|
||||
|
||||
struct pxStretchType
|
||||
|
@ -78,15 +88,47 @@ struct pxStretchType
|
|||
|
||||
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
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
operator wxSizerFlags() const
|
||||
{
|
||||
return Apply();
|
||||
}
|
||||
};
|
||||
|
||||
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, pxStretchType stretch );
|
||||
extern wxSizerFlags operator& ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2 );
|
||||
|
||||
template< typename WinType >
|
||||
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, 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+=( wxWindow& target, int spacer );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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
|
||||
// classes to perform special actions when added to sizers).
|
||||
|
@ -178,6 +223,14 @@ void operator+=( wxWindow& target, WinType* src )
|
|||
template< typename WinType >
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -187,11 +240,31 @@ void operator+=( wxSizer& target, const pxWindowAndFlags<WinType>& src )
|
|||
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 >
|
||||
void operator+=( wxWindow& target, const pxWindowAndFlags<WinType>& src )
|
||||
void operator+=( wxWindow* target, WinType& src )
|
||||
{
|
||||
if( !pxAssert( target.GetSizer() != NULL ) ) return;
|
||||
*target.GetSizer() += src;
|
||||
if( !pxAssert( target != NULL ) ) return;
|
||||
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:
|
||||
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();
|
||||
|
||||
void AddOkCancel( wxSizer& sizer, bool hasApply=false );
|
||||
pxStaticText* Text( const wxString& label );
|
||||
pxStaticHeading* Heading( const wxString& label );
|
||||
void Init();
|
||||
void AddOkCancel( wxSizer& sizer, bool hasApply=false );
|
||||
|
||||
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; }
|
||||
bool HasIdealWidth() const { return m_idealWidth != wxDefaultCoord; }
|
||||
|
||||
protected:
|
||||
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 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 wxFont pxGetFixedFont( int ptsize=8, int weight=wxNORMAL );
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,7 +40,7 @@ struct x86CPU_INFO
|
|||
u32 PhysicalCores;
|
||||
u32 LogicalCores;
|
||||
|
||||
char VendorName[16]; // Vendor/Creator ID
|
||||
char VendorName[16]; // Vendor/Creator ID
|
||||
char TypeName[20]; // cpu type
|
||||
char FamilyName[50]; // the original cpu name
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <wx/app.h>
|
||||
#include "Threading.h"
|
||||
|
||||
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.
|
||||
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)
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
RecursionGuard guard( s_assert_guard );
|
||||
if( guard.IsReentrant() ) return;
|
||||
pxDoAssertFnType* pxDoAssert = pxAssertImpl_LogIt;
|
||||
|
||||
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.
|
||||
wxLogError( wxsFormat( L"%s(%d): Assertion failed in %s: %s\n",
|
||||
file, line, fromUTF8(func).c_str(), msg )
|
||||
);
|
||||
trapit = pxAssertImpl_LogIt( origin, msg );
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __WXDEBUG__
|
||||
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
|
||||
trapit = pxDoAssert( origin, msg );
|
||||
}
|
||||
#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.
|
||||
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)
|
||||
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
||||
// handled via normal yielding methods.
|
||||
|
@ -81,7 +136,7 @@ Threading::PersistentThread::PersistentThread()
|
|||
// This destructor performs basic "last chance" cleanup, which is a blocking join
|
||||
// against the thread. Extending classes should almost always implement their own
|
||||
// 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
|
||||
// like marrying your sister, and then cheating on her with your daughter.
|
||||
|
@ -116,14 +171,24 @@ Threading::PersistentThread::~PersistentThread() throw()
|
|||
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 )
|
||||
|
@ -157,7 +222,29 @@ void Threading::PersistentThread::Start()
|
|||
m_except = NULL;
|
||||
|
||||
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
|
||||
|
@ -165,13 +252,28 @@ void Threading::PersistentThread::Start()
|
|||
// This function should not be called from the owner thread.
|
||||
bool Threading::PersistentThread::Detach()
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf();
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
|
||||
if( _InterlockedExchange( &m_detached, true ) ) return false;
|
||||
pthread_detach( m_thread );
|
||||
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:
|
||||
// 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()
|
||||
|
@ -183,33 +285,40 @@ bool Threading::PersistentThread::Detach()
|
|||
// Parameters:
|
||||
// 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 )
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf();
|
||||
AffinityAssert_DisallowFromSelf( pxDiagSpot );
|
||||
|
||||
{
|
||||
// Prevent simultaneous startup and cancel:
|
||||
ScopedLock startlock( m_lock_start );
|
||||
if( !m_running ) return;
|
||||
// Prevent simultaneous startup and cancel, necessary to avoid
|
||||
ScopedLock startlock( m_lock_start );
|
||||
|
||||
if( m_detached )
|
||||
{
|
||||
Console.Warning( "(Thread Warning) Ignoring attempted cancellation of detached thread." );
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_cancel( m_thread );
|
||||
|
||||
}
|
||||
if( !_basecancel() ) return;
|
||||
|
||||
if( isBlocking )
|
||||
{
|
||||
// FIXME: Add deadlock detection and handling here... ?
|
||||
m_lock_InThread.Wait();
|
||||
WaitOnSelf( m_lock_InThread );
|
||||
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
|
||||
// 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
|
||||
|
@ -218,10 +327,12 @@ void Threading::PersistentThread::Cancel( bool isBlocking )
|
|||
// Returns the return code of the thread.
|
||||
// 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()
|
||||
{
|
||||
AffinityAssert_DisallowFromSelf();
|
||||
m_lock_InThread.Wait();
|
||||
AffinityAssert_DisallowFromSelf(pxDiagSpot);
|
||||
WaitOnSelf( m_lock_InThread );
|
||||
}
|
||||
|
||||
bool Threading::PersistentThread::IsSelf() const
|
||||
|
@ -277,7 +388,7 @@ void Threading::PersistentThread::_selfRunningTest( const wxChar* name ) const
|
|||
//
|
||||
void Threading::PersistentThread::WaitOnSelf( Semaphore& sem ) const
|
||||
{
|
||||
if( !AffinityAssert_DisallowFromSelf() ) return;
|
||||
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return;
|
||||
|
||||
while( true )
|
||||
{
|
||||
|
@ -301,7 +412,7 @@ void Threading::PersistentThread::WaitOnSelf( Semaphore& sem ) const
|
|||
//
|
||||
void Threading::PersistentThread::WaitOnSelf( Mutex& mutex ) const
|
||||
{
|
||||
if( !AffinityAssert_DisallowFromSelf() ) return;
|
||||
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return;
|
||||
|
||||
while( true )
|
||||
{
|
||||
|
@ -314,7 +425,7 @@ static const wxTimeSpan SelfWaitInterval( 0,0,0,333 );
|
|||
|
||||
bool Threading::PersistentThread::WaitOnSelf( Semaphore& sem, const wxTimeSpan& timeout ) const
|
||||
{
|
||||
if( !AffinityAssert_DisallowFromSelf() ) return true;
|
||||
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return true;
|
||||
|
||||
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
|
||||
{
|
||||
if( !AffinityAssert_DisallowFromSelf() ) return true;
|
||||
if( !AffinityAssert_DisallowFromSelf(pxDiagSpot) ) return true;
|
||||
|
||||
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).
|
||||
void Threading::PersistentThread::TestCancel() const
|
||||
{
|
||||
AffinityAssert_AllowFromSelf();
|
||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||
pthread_testcancel();
|
||||
}
|
||||
|
||||
|
@ -393,24 +504,16 @@ void Threading::PersistentThread::_try_virtual_invoke( void (PersistentThread::*
|
|||
}
|
||||
#ifndef PCSX2_DEVBUILD
|
||||
// ----------------------------------------------------------------------------
|
||||
// Allow logic errors to propagate out of the thread in release builds, so that they might be
|
||||
// handled in non-fatal ways. On Devbuilds let them loose, so that they produce debug stack
|
||||
// traces and such.
|
||||
catch( std::logic_error& ex )
|
||||
// Bleh... don't bother with std::exception. runtime_error should catch anything
|
||||
// useful coming out of the core STL libraries anyway, and these are best handled by
|
||||
// the MSVC debugger (or by silent random annoying fail on debug-less linux).
|
||||
/*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() )
|
||||
);
|
||||
}
|
||||
catch( Exception::LogicError& 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 )
|
||||
catch( std::exception& ex )
|
||||
{
|
||||
throw Exception::BaseException( wxsFormat( L"(thread: %s) STL exception: %s\n\t%s",
|
||||
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.
|
||||
void Threading::PersistentThread::_ThreadCleanup()
|
||||
{
|
||||
AffinityAssert_AllowFromSelf();
|
||||
AffinityAssert_AllowFromSelf(pxDiagSpot);
|
||||
_try_virtual_invoke( &PersistentThread::OnCleanupInThread );
|
||||
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
|
||||
// calling ExecuteTaskInThread. This is useful primarily for "base" classes that extend
|
||||
// from PersistentThread, giving them the ability to bind startup code to all threads that
|
||||
// derive from them. (the alternative would have been to make ExecuteTaskInThread a
|
||||
// private member, and provide a new Task executor by a different name).
|
||||
// calling ExecuteTaskInThread, and after the initial InThread lock has been claimed.
|
||||
// This code is also executed within a "safe" environment, where the creating thread is
|
||||
// blocked against m_sem_event. Make sure to do any necessary variable setup here, without
|
||||
// worry that the calling thread might attempt to test the status of those variables
|
||||
// before initialization has completed.
|
||||
//
|
||||
void Threading::PersistentThread::OnStartInThread()
|
||||
{
|
||||
m_running = true;
|
||||
m_detached = false;
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
void Threading::PersistentThread::_internal_execute()
|
||||
{
|
||||
m_lock_InThread.Acquire();
|
||||
OnStartInThread();
|
||||
|
||||
_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 );
|
||||
}
|
||||
|
||||
// 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()
|
||||
{
|
||||
FrankenMutex( m_lock_InThread );
|
||||
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()
|
||||
{
|
||||
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
|
||||
// callback function
|
||||
void* Threading::PersistentThread::_internal_callback( void* itsme )
|
||||
{
|
||||
pxAssert( itsme != NULL );
|
||||
if( !pxAssertDev( itsme != NULL, wxNullChar ) ) return NULL;
|
||||
PersistentThread& owner = *((PersistentThread*)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 )
|
||||
{
|
||||
if( !AffinityAssert_AllowFromSelf() ) return;
|
||||
|
||||
// This feature needs Windows headers and MSVC's SEH support:
|
||||
|
||||
#if defined(_WINDOWS_) && defined (_MSC_VER)
|
||||
|
|
|
@ -81,3 +81,8 @@ void operator+=( wxSizer& target, pxCheckBox& src )
|
|||
{
|
||||
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( m_IsRealized && m_DefaultIdx != -1 )
|
||||
{
|
||||
wxFont def( GetFont() );
|
||||
wxFont def(GetFont());
|
||||
m_objects[m_DefaultIdx].LabelObj->SetFont( def );
|
||||
m_objects[m_DefaultIdx].LabelObj->SetForegroundColour( GetForegroundColour() );
|
||||
}
|
||||
|
@ -166,6 +166,20 @@ pxRadioPanel& pxRadioPanel::SetDefault( int idx )
|
|||
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
|
||||
{
|
||||
if( !VerifyRealizedState() ) return 0;
|
||||
|
|
|
@ -131,3 +131,8 @@ void operator+=( wxSizer& target, pxStaticText& src )
|
|||
{
|
||||
src.AddTo( target );
|
||||
}
|
||||
|
||||
void operator+=( wxSizer* target, pxStaticText& src )
|
||||
{
|
||||
src.AddTo( target );
|
||||
}
|
||||
|
|
|
@ -99,7 +99,12 @@ wxSizerFlags pxStretchType::Apply( wxSizerFlags flags ) const
|
|||
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 );
|
||||
wxSizerFlags retval;
|
||||
|
@ -118,11 +123,8 @@ wxSizerFlags operator , ( const wxSizerFlags& _flgs, const wxSizerFlags& _flgs2
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*wxSizerFlags operator | ( const wxSizerFlags& _flgs, pxStretchType stretch )
|
||||
{
|
||||
return stretch.Apply( _flgs );
|
||||
}*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Reference/Handle versions!
|
||||
|
||||
void operator+=( wxSizer& target, wxWindow* src )
|
||||
{
|
||||
|
@ -148,6 +150,23 @@ void operator+=( wxSizer& target, int 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 )
|
||||
{
|
||||
|
@ -431,3 +450,14 @@ void pxSetToolTip( wxWindow& wind, const wxString& 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
|
||||
// =====================================================================================================
|
||||
|
||||
HashTools::HashMap< wxWindowID, int > m_DialogIdents( 0, wxID_ANY );
|
||||
|
||||
bool pxDialogExists( wxWindowID id )
|
||||
bool pxDialogExists( const wxString& name )
|
||||
{
|
||||
int dest = 0;
|
||||
m_DialogIdents.TryGetValue( id, dest );
|
||||
return (dest > 0);
|
||||
return wxFindWindowByName( name ) != NULL;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -44,20 +40,41 @@ IMPLEMENT_DYNAMIC_CLASS(wxDialogWithHelpers, wxDialog)
|
|||
|
||||
wxDialogWithHelpers::wxDialogWithHelpers()
|
||||
{
|
||||
m_idealWidth = wxDefaultCoord;
|
||||
m_hasContextHelp = false;
|
||||
m_extraButtonSizer = NULL;
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, int id, const wxString& title, bool hasContextHelp, const wxPoint& pos, const wxSize& size )
|
||||
: wxDialog( parent, id, title, pos, size , wxDEFAULT_DIALOG_STYLE) //, (wxCAPTION | wxMAXIMIZE | wxCLOSE_BOX | wxRESIZE_BORDER) ), // flags for resizable dialogs, currently unused.
|
||||
wxDialogWithHelpers::wxDialogWithHelpers( wxWindow* parent, const wxString& title, bool hasContextHelp, bool resizable )
|
||||
: 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_extraButtonSizer = NULL;
|
||||
|
||||
m_hasContextHelp = hasContextHelp;
|
||||
if( m_hasContextHelp )
|
||||
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!)
|
||||
// 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)
|
||||
|
||||
|
||||
//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()];
|
||||
pxAssert( m_DialogIdents[GetId()] >= 0 );
|
||||
Fit();
|
||||
|
||||
// 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 )
|
||||
|
@ -85,6 +142,19 @@ pxStaticHeading* wxDialogWithHelpers::Heading( const wxString& 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)
|
||||
{
|
||||
//evt.Skip();
|
||||
|
@ -119,7 +189,7 @@ void wxDialogWithHelpers::AddOkCancel( wxSizer &sizer, bool hasApply )
|
|||
flex.AddGrowableCol( 1, 15 );
|
||||
|
||||
flex += m_extraButtonSizer | pxAlignLeft;
|
||||
flex += s_buttons | pxExpand, pxCenter;
|
||||
flex += s_buttons | (pxExpand & pxCenter);
|
||||
|
||||
sizer += flex | StdExpand();
|
||||
|
||||
|
|
|
@ -592,7 +592,7 @@ $memcpy_final:
|
|||
// (zerofrog)
|
||||
u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize)
|
||||
{
|
||||
assert( (cmpsize&7) == 0 );
|
||||
pxAssert( (cmpsize&7) == 0 );
|
||||
|
||||
__asm {
|
||||
push esi
|
||||
|
@ -766,7 +766,7 @@ End:
|
|||
// returns the xor of all elements, cmpsize has to be mult of 8
|
||||
void memxor_mmx(void* dst, const void* src1, int cmpsize)
|
||||
{
|
||||
assert( (cmpsize&7) == 0 );
|
||||
pxAssert( (cmpsize&7) == 0 );
|
||||
|
||||
__asm {
|
||||
mov ecx, cmpsize
|
||||
|
|
|
@ -745,7 +745,7 @@ __forceinline void cdvdReadInterrupt()
|
|||
// 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
|
||||
|
||||
assert((int)cdvd.ReadTime > 0 );
|
||||
pxAssume((int)cdvd.ReadTime > 0 );
|
||||
CDVDREAD_INT(cdvd.ReadTime/4);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -340,7 +340,7 @@ static __forceinline void frameLimit()
|
|||
static __forceinline void VSyncStart(u32 sCycle)
|
||||
{
|
||||
Cpu->CheckExecutionState();
|
||||
SysCoreThread::Get().VsyncInThread();
|
||||
GetCoreThread().VsyncInThread();
|
||||
|
||||
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
|
||||
// done in a more optimized fashion.
|
||||
|
||||
while( true )
|
||||
{
|
||||
execI();
|
||||
}
|
||||
try {
|
||||
while( true )
|
||||
execI();
|
||||
} catch( Exception::ForceDispatcherReg& ) { }
|
||||
}
|
||||
|
||||
static void intCheckExecutionState()
|
||||
{
|
||||
SysCoreThread::Get().StateCheckInThread();
|
||||
if( GetCoreThread().HasPendingStateChangeRequest() )
|
||||
throw Exception::ForceDispatcherReg();
|
||||
}
|
||||
|
||||
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() );
|
||||
|
||||
if( folders[pid].IsEmpty() )
|
||||
throw Exception::InvalidArgument( "Empty plugin filename." );
|
||||
throw Exception::PluginInitError( pi->id, "Empty plugin filename." );
|
||||
|
||||
m_info[pid].Filename = folders[pid];
|
||||
|
||||
|
@ -985,6 +985,14 @@ void PluginManager::Close( PluginsEnum_t pid )
|
|||
|
||||
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..." );
|
||||
|
||||
// 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
|
||||
|
||||
static bool cpuIsInitialized = false;
|
||||
static const uint eeWaitCycles = 3072;
|
||||
|
||||
bool eeEventTestIsActive = false;
|
||||
|
@ -52,10 +51,6 @@ void cpuReset()
|
|||
if( GetMTGS().IsOpen() )
|
||||
GetMTGS().WaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||
|
||||
SysClearExecutionCache();
|
||||
|
||||
cpuIsInitialized = true;
|
||||
|
||||
memReset();
|
||||
psxMemReset();
|
||||
vuMicroMemReset();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* 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.
|
||||
* 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;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
|
@ -22,8 +22,11 @@
|
|||
|
||||
class _BaseStateThread;
|
||||
|
||||
// Used to hold the current state backup (fullcopy of PS2 memory and plugin states).
|
||||
static SafeArray<u8> state_buffer;
|
||||
|
||||
_BaseStateThread* current_state_thread = NULL;
|
||||
|
||||
// Simple lock boolean for the state buffer being in use by a thread.
|
||||
static NonblockingMutex state_buffer_lock;
|
||||
|
||||
|
@ -56,9 +59,22 @@ class _BaseStateThread : public PersistentThread
|
|||
protected:
|
||||
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:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -67,14 +83,18 @@ protected:
|
|||
m_bind_OnExit( wxGetApp().Source_AppStatus(), EventListener<AppEventType>( this, StateThread_OnAppStatus ) )
|
||||
{
|
||||
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()
|
||||
{
|
||||
if( !state_buffer_lock.TryAcquire() )
|
||||
throw Exception::CancelEvent( m_name + L"request ignored: state copy buffer is already locked!" );
|
||||
|
||||
|
||||
current_state_thread = this;
|
||||
m_isStarted = true;
|
||||
_parent::OnStart();
|
||||
}
|
||||
|
||||
|
@ -83,6 +103,7 @@ protected:
|
|||
wxCommandEvent evt( pxEVT_FreezeThreadFinished );
|
||||
evt.SetClientData( this );
|
||||
evt.SetInt( type );
|
||||
evt.SetExtraLong( m_resume_when_done );
|
||||
wxGetApp().AddPendingEvent( evt );
|
||||
}
|
||||
|
||||
|
@ -107,7 +128,7 @@ protected:
|
|||
{
|
||||
_parent::OnStart();
|
||||
++sys_resume_lock;
|
||||
CoreThread.Pause();
|
||||
m_resume_when_done = CoreThread.Pause();
|
||||
}
|
||||
|
||||
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
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -171,14 +155,15 @@ protected:
|
|||
gzFile m_gzfp;
|
||||
|
||||
public:
|
||||
StateThread_ZipToDisk( FnType_OnThreadComplete* onFinished, const wxString& file ) :
|
||||
_BaseStateThread( "ZipToDisk", onFinished )
|
||||
, m_filename( file )
|
||||
, m_gzfp( NULL )
|
||||
StateThread_ZipToDisk( FnType_OnThreadComplete* onFinished, bool resume_done, const wxString& file )
|
||||
: _BaseStateThread( "ZipToDisk", onFinished )
|
||||
, m_filename( file )
|
||||
{
|
||||
m_gzfp = NULL;
|
||||
m_resume_when_done = resume_done;
|
||||
}
|
||||
|
||||
~StateThread_ZipToDisk() throw()
|
||||
virtual ~StateThread_ZipToDisk() throw()
|
||||
{
|
||||
if( m_gzfp != NULL ) gzclose( m_gzfp );
|
||||
}
|
||||
|
@ -232,15 +217,16 @@ protected:
|
|||
bool m_finished;
|
||||
|
||||
public:
|
||||
StateThread_UnzipFromDisk( FnType_OnThreadComplete* onFinished, const wxString& file ) :
|
||||
_BaseStateThread( "UnzipFromDisk", onFinished )
|
||||
, m_filename( file )
|
||||
, m_gzfp( NULL )
|
||||
, m_finished( false )
|
||||
StateThread_UnzipFromDisk( FnType_OnThreadComplete* onFinished, bool resume_done, const wxString& file )
|
||||
: _BaseStateThread( "UnzipFromDisk", onFinished )
|
||||
, m_filename( file )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
@ -297,32 +283,17 @@ void Pcsx2App::OnFreezeThreadFinished( wxCommandEvent& 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 )
|
||||
{
|
||||
// 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();
|
||||
CoreThread.RecoverState();
|
||||
if( evt.GetExtraLong() ) CoreThread.Resume();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -331,21 +302,13 @@ void OnFinished_ZipToDisk( const wxCommandEvent& evt )
|
|||
Console.Warning( "Cannot save state to disk: empty filename specified." );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -362,8 +325,8 @@ void StateCopy_SaveToFile( const wxString& file )
|
|||
void StateCopy_LoadFromFile( const wxString& file )
|
||||
{
|
||||
if( state_buffer_lock.IsLocked() ) return;
|
||||
CoreThread.Pause();
|
||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
||||
bool resume_when_done = CoreThread.Pause();
|
||||
(new StateThread_UnzipFromDisk( OnFinished_Resume, resume_when_done, file ))->Start();
|
||||
}
|
||||
|
||||
// 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.Indent().WriteLn( Color_StrongGreen, L"filename: %s", file.c_str() );
|
||||
|
||||
CoreThread.Pause();
|
||||
(new StateThread_UnzipFromDisk( OnFinished_Restore, file ))->Start();
|
||||
bool resume_when_done = CoreThread.Pause();
|
||||
(new StateThread_UnzipFromDisk( OnFinished_Resume, resume_when_done, file ))->Start();
|
||||
}
|
||||
|
||||
bool StateCopy_IsValid()
|
||||
{
|
||||
return !state_buffer.IsDisposed();
|
||||
return !state_buffer.IsDisposed();
|
||||
}
|
||||
|
||||
const SafeArray<u8>* StateCopy_GetBuffer()
|
||||
|
@ -412,20 +375,45 @@ const SafeArray<u8>* StateCopy_GetBuffer()
|
|||
void StateCopy_FreezeToMem()
|
||||
{
|
||||
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;
|
||||
new StateThread_Thaw( OnFinished_Restore );
|
||||
if( state_buffer_lock.TryAcquire() ) return;
|
||||
|
||||
/*
|
||||
// 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();
|
||||
state_buffer.Dispose();
|
||||
state_buffer_lock.Release();
|
||||
}
|
||||
|
||||
|
@ -439,3 +427,4 @@ bool StateCopy_IsBusy()
|
|||
{
|
||||
return state_buffer_lock.IsLocked();
|
||||
}
|
||||
|
|
@ -204,7 +204,9 @@ public:
|
|||
extern bool StateCopy_IsValid();
|
||||
|
||||
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_LoadFromFile( const wxString& file );
|
||||
extern void StateCopy_SaveToSlot( uint num );
|
||||
|
|
|
@ -57,7 +57,7 @@ TraceLogFilters& SetTraceConfig()
|
|||
|
||||
|
||||
// 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,
|
||||
SVN_REV, SVN_MODS ? "(modded)" : ""
|
||||
|
@ -66,8 +66,6 @@ void SysDetect()
|
|||
Console.WriteLn( "Savestate version: 0x%x", g_SaveVersion);
|
||||
Console.Newline();
|
||||
|
||||
cpudetectInit();
|
||||
|
||||
Console.WriteLn( Color_StrongBlack, "x86-32 Init:" );
|
||||
|
||||
Console.Indent().WriteLn(
|
||||
|
@ -149,13 +147,15 @@ CpuInitializer< CpuType >::CpuInitializer()
|
|||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
Console.Error( L"MicroVU0 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
|
||||
MyCpu->Shutdown();
|
||||
Console.Error( L"CPU provider error:\n\t" + ex.FormatDiagnosticMessage() );
|
||||
if( MyCpu )
|
||||
MyCpu = NULL;
|
||||
}
|
||||
catch( std::runtime_error& ex )
|
||||
{
|
||||
Console.Error( L"MicroVU0 Recompiler Allocation Failed (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
|
||||
MyCpu->Shutdown();
|
||||
Console.Error( L"CPU provider error (STL Exception)\n\tDetails:" + fromUTF8( ex.what() ) );
|
||||
if( MyCpu )
|
||||
MyCpu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ protected:
|
|||
// implemented by the provisioning interface.
|
||||
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!
|
||||
|
||||
|
||||
|
@ -106,6 +106,7 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
|||
//
|
||||
|
||||
class pxMessageBoxEvent;
|
||||
class pxAssertionEvent;
|
||||
|
||||
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 int Assertion( const wxString& text, const wxString& stacktrace );
|
||||
extern void Except( const Exception::BaseException& src );
|
||||
}
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE( pxEVT_MSGBOX, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_CallStackBox, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEVT_ASSERTION, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
|
|
@ -56,6 +56,18 @@ void SysCoreThread::Cancel( bool isBlocking )
|
|||
{
|
||||
m_CoreCancelDamnit = true;
|
||||
_parent::Cancel();
|
||||
ReleaseResumeLock();
|
||||
}
|
||||
|
||||
bool SysCoreThread::Cancel( const wxTimeSpan& span )
|
||||
{
|
||||
m_CoreCancelDamnit = true;
|
||||
if( _parent::Cancel( span ) )
|
||||
{
|
||||
ReleaseResumeLock();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SysCoreThread::Start()
|
||||
|
@ -78,21 +90,26 @@ void SysCoreThread::Start()
|
|||
void SysCoreThread::OnResumeReady()
|
||||
{
|
||||
if( m_resetVirtualMachine )
|
||||
{
|
||||
cpuReset();
|
||||
m_resetVirtualMachine = false;
|
||||
m_hasValidState = false;
|
||||
}
|
||||
m_hasValidState = false;
|
||||
|
||||
if( !m_hasValidState )
|
||||
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()
|
||||
{
|
||||
Suspend();
|
||||
m_resetVirtualMachine = true;
|
||||
m_hasValidState = false;
|
||||
m_resetVirtualMachine = true;
|
||||
m_hasValidState = false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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_resetVsyncTimers = ( src.GS != EmuConfig.GS );
|
||||
|
||||
|
@ -213,10 +231,50 @@ struct ScopedBool_ClearOnError
|
|||
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()
|
||||
{
|
||||
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();
|
||||
|
||||
ScopedBool_ClearOnError sbcoe( m_hasValidState );
|
||||
|
@ -262,24 +320,6 @@ void SysCoreThread::CpuInitializeMess()
|
|||
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
|
||||
// PS2 core plugins.
|
||||
void SysCoreThread::DispatchKeyEventToUI( const keyEvent& evt )
|
||||
|
@ -315,10 +355,11 @@ void SysCoreThread::StateCheckInThread()
|
|||
{
|
||||
GetMTGS().RethrowException();
|
||||
_parent::StateCheckInThread();
|
||||
|
||||
if( !m_hasValidState )
|
||||
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()
|
||||
|
@ -330,9 +371,10 @@ void SysCoreThread::ExecuteTaskInThread()
|
|||
m_mxcsr_saved.bitmask = _mm_getcsr();
|
||||
|
||||
PCSX2_PAGEFAULT_PROTECT {
|
||||
StateCheckInThread();
|
||||
SetCPUState( EmuConfig.Cpu.sseMXCSR, EmuConfig.Cpu.sseVUMXCSR );
|
||||
Cpu->Execute();
|
||||
do {
|
||||
StateCheckInThread();
|
||||
Cpu->Execute();
|
||||
} while( true );
|
||||
} PCSX2_PAGEFAULT_EXCEPT;
|
||||
}
|
||||
|
||||
|
@ -347,8 +389,7 @@ void SysCoreThread::OnResumeInThread( bool isSuspended )
|
|||
if( g_plugins != NULL )
|
||||
g_plugins->Open();
|
||||
|
||||
if( isSuspended )
|
||||
CpuInitializeMess();
|
||||
CpuInitializeMess();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,22 +36,9 @@ SysThreadBase::~SysThreadBase() throw()
|
|||
void SysThreadBase::Start()
|
||||
{
|
||||
_parent::Start();
|
||||
m_ExecMode = ExecMode_Closing;
|
||||
|
||||
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),
|
||||
"Unexpected thread status during SysThread startup."
|
||||
);
|
||||
|
@ -118,7 +105,7 @@ bool SysThreadBase::Suspend( bool isBlocking )
|
|||
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();
|
||||
}
|
||||
|
||||
|
@ -164,7 +151,7 @@ bool SysThreadBase::Pause()
|
|||
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();
|
||||
}
|
||||
|
@ -247,7 +234,7 @@ void SysThreadBase::OnStartInThread()
|
|||
{
|
||||
m_RunningLock.Acquire();
|
||||
_parent::OnStartInThread();
|
||||
m_ResumeEvent.Post();
|
||||
m_ExecMode = ExecMode_Closing;
|
||||
}
|
||||
|
||||
void SysThreadBase::OnCleanupInThread()
|
||||
|
|
|
@ -20,22 +20,6 @@
|
|||
|
||||
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
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -208,8 +192,10 @@ public:
|
|||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
virtual void OnResumeReady();
|
||||
virtual void Reset();
|
||||
virtual void RecoverState();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
|
||||
virtual bool Cancel( const wxTimeSpan& timeout );
|
||||
|
||||
bool HasValidState()
|
||||
{
|
||||
return m_hasValidState;
|
||||
|
|
|
@ -65,14 +65,12 @@ void __fastcall vu0ExecMicro(u32 addr) {
|
|||
}
|
||||
|
||||
void VU0unknown() {
|
||||
assert(0);
|
||||
|
||||
pxFailDev("Unknown VU micromode opcode called");
|
||||
CPU_LOG("Unknown VU micromode opcode called");
|
||||
}
|
||||
|
||||
void VU0regsunknown(_VURegsNum *VUregsn) {
|
||||
assert(0);
|
||||
|
||||
pxFailDev("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
|
||||
// are valid for logging or not. (see DisVU1Micro.cpp, etc) [kinda hacky, might
|
||||
// be removed in the future]
|
||||
bool IsInterpreter;
|
||||
bool IsInterpreter;
|
||||
|
||||
public:
|
||||
BaseCpuProvider()
|
||||
|
@ -105,6 +105,7 @@ public:
|
|||
|
||||
protected:
|
||||
BaseVUmicroCPU() {}
|
||||
virtual ~BaseVUmicroCPU() throw() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -115,6 +116,7 @@ class InterpVU0 : public BaseVUmicroCPU
|
|||
{
|
||||
public:
|
||||
InterpVU0();
|
||||
virtual ~InterpVU0() throw() { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "intVU0"; }
|
||||
wxString GetLongName() const { return L"VU0 Interpreter"; }
|
||||
|
@ -132,6 +134,7 @@ class InterpVU1 : public BaseVUmicroCPU
|
|||
{
|
||||
public:
|
||||
InterpVU1();
|
||||
virtual ~InterpVU1() throw() { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "intVU1"; }
|
||||
wxString GetLongName() const { return L"VU1 Interpreter"; }
|
||||
|
@ -152,6 +155,7 @@ class recMicroVU0 : public BaseVUmicroCPU
|
|||
{
|
||||
public:
|
||||
recMicroVU0();
|
||||
virtual ~recMicroVU0() throw() { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "mVU0"; }
|
||||
wxString GetLongName() const { return L"microVU0 Recompiler"; }
|
||||
|
@ -169,6 +173,7 @@ class recMicroVU1 : public BaseVUmicroCPU
|
|||
{
|
||||
public:
|
||||
recMicroVU1();
|
||||
virtual ~recMicroVU1() throw() { Shutdown(); }
|
||||
|
||||
const char* GetShortName() const { return "mVU1"; }
|
||||
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* 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);
|
||||
pxAssert(ret > 0);
|
||||
pxAssume(ret > 0);
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
|
@ -752,7 +752,7 @@ void vif0Write32(u32 mem, u32 value)
|
|||
case VIF0_R1:
|
||||
case VIF0_R2:
|
||||
case VIF0_R3:
|
||||
pxAssert((mem&0xf) == 0);
|
||||
pxAssume((mem&0xf) == 0);
|
||||
g_vifmask.Row0[(mem>>4) & 3] = value;
|
||||
break;
|
||||
|
||||
|
@ -760,7 +760,7 @@ void vif0Write32(u32 mem, u32 value)
|
|||
case VIF0_C1:
|
||||
case VIF0_C2:
|
||||
case VIF0_C3:
|
||||
pxAssert((mem&0xf) == 0);
|
||||
pxAssume((mem&0xf) == 0);
|
||||
g_vifmask.Col0[(mem>>4) & 3] = value;
|
||||
break;
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ static __forceinline void vif1mpgTransfer(u32 addr, u32 *data, int size)
|
|||
fwrite(data, 1, size*4, f);
|
||||
fclose(f);
|
||||
}*/
|
||||
pxAssert(VU1.Micro > 0);
|
||||
pxAssume(VU1.Micro > 0);
|
||||
if (memcmp(VU1.Micro + addr, data, size << 2))
|
||||
{
|
||||
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* 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);
|
||||
pxAssert(ret > 0);
|
||||
pxAssume(ret > 0);
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
|
@ -1143,7 +1143,7 @@ void vif1Write32(u32 mem, u32 value)
|
|||
case VIF1_R1:
|
||||
case VIF1_R2:
|
||||
case VIF1_R3:
|
||||
pxAssert((mem&0xf) == 0);
|
||||
pxAssume((mem&0xf) == 0);
|
||||
g_vifmask.Row1[(mem>>4) & 3] = value;
|
||||
break;
|
||||
|
||||
|
@ -1151,7 +1151,7 @@ void vif1Write32(u32 mem, u32 value)
|
|||
case VIF1_C1:
|
||||
case VIF1_C2:
|
||||
case VIF1_C3:
|
||||
pxAssert((mem&0xf) == 0);
|
||||
pxAssume((mem&0xf) == 0);
|
||||
g_vifmask.Col1[(mem>>4) & 3] = value;
|
||||
break;
|
||||
|
||||
|
|
|
@ -283,9 +283,7 @@ template<const u32 VIFdmanum> u32 VIFalign(u32 *data, vifCode *v, u32 size)
|
|||
vif = &vif1;
|
||||
vifRow = g_vifmask.Row1;
|
||||
}
|
||||
#ifdef PCSX2_DEBUG
|
||||
pxAssert(v->addr < memsize);
|
||||
#endif
|
||||
pxAssume(v->addr < memsize);
|
||||
|
||||
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;
|
||||
const u32 memlimit = vif_size(VIFdmanum);
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
u32 memsize = memlimit;
|
||||
#endif
|
||||
pxDebugCode( u32 memsize = memlimit );
|
||||
|
||||
_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;
|
||||
vif = &vif0;
|
||||
vifRow = g_vifmask.Row0;
|
||||
#ifdef PCSX2_DEBUG
|
||||
pxAssert(v->addr < memsize);
|
||||
#endif
|
||||
pxDebugCode( pxAssume(v->addr < memsize) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -501,9 +495,7 @@ template<const u32 VIFdmanum> void VIFunpack(u32 *data, vifCode *v, u32 size)
|
|||
vifMaskRegs = g_vif1Masks;
|
||||
vif = &vif1;
|
||||
vifRow = g_vifmask.Row1;
|
||||
#ifdef PCSX2_DEBUG
|
||||
pxAssert(v->addr < memsize);
|
||||
#endif
|
||||
pxDebugCode( pxAssume(v->addr < memsize) );
|
||||
}
|
||||
|
||||
dest = (u32*)(VU->Mem + v->addr);
|
||||
|
@ -523,9 +515,7 @@ template<const u32 VIFdmanum> void VIFunpack(u32 *data, vifCode *v, u32 size)
|
|||
|
||||
size <<= 2;
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
memsize = size;
|
||||
#endif
|
||||
pxDebugCode( memsize = size );
|
||||
|
||||
if (vifRegs->cycle.cl >= vifRegs->cycle.wl) // skipping write
|
||||
{
|
||||
|
|
|
@ -38,7 +38,6 @@ class AppCoreThread;
|
|||
#include "System.h"
|
||||
#include "System/SysThreads.h"
|
||||
|
||||
|
||||
typedef void FnType_OnThreadComplete(const wxCommandEvent& evt);
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
|
@ -151,14 +150,6 @@ enum MenuIdentifiers
|
|||
MenuId_Config_ResetAll,
|
||||
};
|
||||
|
||||
enum DialogIdentifiers
|
||||
{
|
||||
DialogId_CoreSettings = 0x800,
|
||||
DialogId_BiosSelector,
|
||||
DialogId_LogOptions,
|
||||
DialogId_About,
|
||||
};
|
||||
|
||||
enum AppEventType
|
||||
{
|
||||
// Maybe this will be expanded upon later..?
|
||||
|
@ -331,9 +322,9 @@ struct MsgboxEventResult
|
|||
Semaphore WaitForMe;
|
||||
int result;
|
||||
|
||||
MsgboxEventResult() :
|
||||
WaitForMe(), result( 0 )
|
||||
MsgboxEventResult()
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -406,7 +397,7 @@ public:
|
|||
|
||||
void PostPadKey( wxKeyEvent& evt );
|
||||
void PostMenuAction( MenuIdentifiers menu_id ) const;
|
||||
int ThreadedModalDialog( DialogIdentifiers dialogId );
|
||||
int IssueModalDialog( const wxString& dlgName );
|
||||
|
||||
bool PrepForExit( bool canCancel );
|
||||
|
||||
|
@ -532,6 +523,7 @@ public:
|
|||
virtual bool Suspend( bool isBlocking=true );
|
||||
virtual void Resume();
|
||||
virtual void Reset();
|
||||
virtual void Cancel( bool isBlocking=true );
|
||||
virtual void StateCheckInThread();
|
||||
virtual void ApplySettings( const Pcsx2Config& src );
|
||||
virtual void ChangeCdvdSource( CDVD_SourceType type );
|
||||
|
@ -610,6 +602,9 @@ public:
|
|||
virtual ~SaveSinglePluginHelper() throw();
|
||||
};
|
||||
|
||||
|
||||
extern pxDoAssertFnType AppDoAssert;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// External App-related Globals and Shortcuts
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -18,18 +18,27 @@
|
|||
|
||||
#include <wx/stackwalk.h>
|
||||
|
||||
|
||||
static wxString pxGetStackTrace()
|
||||
static wxString pxGetStackTrace( const FnChar_t* calledFrom )
|
||||
{
|
||||
wxString stackTrace;
|
||||
|
||||
class StackDump : public wxStackWalker
|
||||
{
|
||||
protected:
|
||||
wxString m_stackTrace;
|
||||
wxString m_stackTrace;
|
||||
wxString m_srcFuncName;
|
||||
bool m_ignoreDone;
|
||||
int m_skipped;
|
||||
|
||||
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; }
|
||||
|
||||
|
@ -38,92 +47,108 @@ static wxString pxGetStackTrace()
|
|||
{
|
||||
wxString name( frame.GetName() );
|
||||
if( name.IsEmpty() )
|
||||
{
|
||||
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 ",
|
||||
wx_truncate_cast(int, frame.GetLevel()), name.c_str()
|
||||
m_ignoreDone = true;
|
||||
}
|
||||
|
||||
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.
|
||||
static const int maxLines = 20;
|
||||
|
||||
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;
|
||||
StackDump dump( calledFrom );
|
||||
dump.Walk( 3 );
|
||||
return dump.GetStackTrace();
|
||||
}
|
||||
|
||||
static __threadlocal bool _reentrant_lock = false;
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
|
||||
static __threadlocal int _reentrant_lock = 0;
|
||||
|
||||
// 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
|
||||
// via messages.
|
||||
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.
|
||||
static bool disableAsserts = false;
|
||||
if( disableAsserts ) return;
|
||||
// Re-entrant assertions are bad mojo -- trap immediately.
|
||||
RecursionGuard guard( _reentrant_lock );
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
_reentrant_lock = true;
|
||||
#endif
|
||||
|
||||
wxString dbgmsg;
|
||||
dbgmsg.reserve( 2048 );
|
||||
bool AppDoAssert( const DiagnosticOrigin& origin, const wxChar *msg )
|
||||
{
|
||||
// Used to allow the user to suppress future assertions during this application's session.
|
||||
static bool disableAsserts = false;
|
||||
if( disableAsserts ) return false;
|
||||
|
||||
wxString message;
|
||||
if( msg == NULL )
|
||||
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() );
|
||||
wxString trace( pxGetStackTrace(origin.function) );
|
||||
wxString dbgmsg( origin.ToString( msg ) );
|
||||
|
||||
wxMessageOutputDebug().Printf( dbgmsg );
|
||||
|
||||
Console.Error( dbgmsg );
|
||||
Console.WriteLn( trace );
|
||||
|
||||
int retval = Msgbox::Assertion( dbgmsg, trace );
|
||||
|
||||
switch( retval )
|
||||
{
|
||||
case wxID_YES:
|
||||
wxTrap();
|
||||
break;
|
||||
|
||||
case wxID_NO: break;
|
||||
|
||||
case wxID_CANCEL: // ignores future assertions.
|
||||
disableAsserts = true;
|
||||
break;
|
||||
}
|
||||
wxString windowmsg( L"Assertion failed: " );
|
||||
if( msg != NULL )
|
||||
windowmsg += msg;
|
||||
else if( origin.condition != NULL )
|
||||
windowmsg += origin.condition;
|
||||
|
||||
_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" )
|
||||
{
|
||||
LanguageId = wxLANGUAGE_DEFAULT;
|
||||
RecentFileCount = 6;
|
||||
RecentIsoCount = 12;
|
||||
Listbook_ImageSize = 32;
|
||||
Toolbar_ImageSize = 24;
|
||||
Toolbar_ShowLabels = true;
|
||||
|
@ -378,7 +378,7 @@ void AppConfig::LoadSaveRootItems( IniInterface& ini )
|
|||
IniEntry( MainGuiPosition );
|
||||
IniEntry( SettingsTabName );
|
||||
ini.EnumEntry( L"LanguageId", LanguageId, NULL, defaults.LanguageId );
|
||||
IniEntry( RecentFileCount );
|
||||
IniEntry( RecentIsoCount );
|
||||
IniEntry( DeskTheme );
|
||||
IniEntry( Listbook_ImageSize );
|
||||
IniEntry( Toolbar_ImageSize );
|
||||
|
|
|
@ -154,7 +154,7 @@ public:
|
|||
// Current language in use (correlates to a wxWidgets wxLANGUAGE specifier)
|
||||
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)
|
||||
// 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::Cancel();
|
||||
}
|
||||
|
||||
void AppCoreThread::Cancel( bool isBlocking )
|
||||
{
|
||||
if( !_parent::Cancel( wxTimeSpan( 0,0,1,0 ) ) )
|
||||
{
|
||||
// Possible deadlock!
|
||||
throw Exception::ThreadTimedOut( this );
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
if( !IsDebugBuild ) return;
|
||||
|
@ -81,8 +107,7 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
|
||||
if (IOP_ENABLE_SIF_HACK == 1)
|
||||
{
|
||||
wxDialogWithHelpers hackedVersion( NULL, wxID_ANY, _("It will devour your young! - PCSX2 Shub-Niggurath edition"), false );
|
||||
hackedVersion.SetIdealWidth( 575 );
|
||||
wxDialogWithHelpers hackedVersion( NULL, _("It will devour your young! - PCSX2 Shub-Niggurath edition"), wxVERTICAL );
|
||||
|
||||
hackedVersion.SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||
hackedVersion += new pxStaticText( &hackedVersion,
|
||||
|
@ -92,8 +117,6 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
);
|
||||
|
||||
hackedVersion += new wxButton( &hackedVersion, wxID_OK ) | pxSizerFlags::StdCenter();
|
||||
hackedVersion.Fit();
|
||||
hackedVersion.CentreOnScreen();
|
||||
hackedVersion.ShowModal();
|
||||
}
|
||||
|
||||
|
@ -101,8 +124,7 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
{
|
||||
// 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 );
|
||||
preAlpha.SetIdealWidth( 575 );
|
||||
wxDialogWithHelpers preAlpha( NULL, _("It might devour your kittens! - PCSX2 0.9.7 Pre-Alpha"), wxVERTICAL );
|
||||
|
||||
preAlpha.SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||
preAlpha += new pxStaticText( &preAlpha,
|
||||
|
@ -113,8 +135,6 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
);
|
||||
|
||||
preAlpha += new wxButton( &preAlpha, wxID_OK ) | pxSizerFlags::StdCenter();
|
||||
preAlpha.Fit();
|
||||
preAlpha.CentreOnScreen();
|
||||
preAlpha.ShowModal();
|
||||
|
||||
// first time startup, so give the user the choice of user mode:
|
||||
|
@ -243,6 +263,15 @@ typedef void (wxEvtHandler::*pxMessageBoxEventFunction)(pxMessageBoxEvent&);
|
|||
// ------------------------------------------------------------------------
|
||||
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();
|
||||
EnableAllLogging();
|
||||
|
||||
|
@ -253,12 +282,6 @@ bool Pcsx2App::OnInit()
|
|||
m_StderrRedirHandle = NewPipeRedir(stderr);
|
||||
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_SysExecute, wxCommandEventHandler( Pcsx2App::OnSysExecute ) );
|
||||
|
||||
|
@ -286,9 +309,21 @@ bool Pcsx2App::OnInit()
|
|||
|
||||
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();
|
||||
AppConfig_OnChangedSettingsFolder();
|
||||
|
||||
CpuCheckSSE2();
|
||||
|
||||
m_MainFrame = new MainEmuFrame( NULL, L"PCSX2" );
|
||||
m_MainFrame->PushEventHandler( &GetRecentIsoList() );
|
||||
|
||||
|
@ -307,7 +342,8 @@ bool Pcsx2App::OnInit()
|
|||
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
|
||||
m_MainFrame->Show();
|
||||
|
||||
SysDetect();
|
||||
SysLogMachineCaps();
|
||||
|
||||
AppApplySettings();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
@ -317,47 +353,72 @@ bool Pcsx2App::OnInit()
|
|||
|
||||
m_CoreAllocs = new SysCoreAllocations();
|
||||
|
||||
|
||||
if( m_CoreAllocs->HadSomeFailures( g_Conf->EmuOptions.Cpu.Recompiler ) )
|
||||
{
|
||||
// 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
|
||||
// popping up this dialog.
|
||||
|
||||
wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)"), wxVERTICAL );
|
||||
|
||||
// TODO : This should be redone using the ExtensibleConfirmation, and a sub-window
|
||||
// (static text or something with a vertical scrollbar).
|
||||
exconf += 12;
|
||||
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() )
|
||||
{
|
||||
message += L"\t* R5900 (EE)\n";
|
||||
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
|
||||
|
||||
g_Conf->EmuOptions.Recompiler.EnableEE = false;
|
||||
}
|
||||
|
||||
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() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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...
|
||||
|
||||
/*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."
|
||||
);*/
|
||||
|
||||
if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
|
||||
return false;
|
||||
//if( !Msgbox::OkCancel( message, _("PCSX2 Initialization Error"), wxICON_ERROR ) )
|
||||
// return false;
|
||||
}
|
||||
|
||||
LoadPluginsPassive( NULL );
|
||||
|
@ -408,13 +469,16 @@ void Pcsx2App::CleanupMess()
|
|||
if( m_CorePlugins )
|
||||
m_CorePlugins->Shutdown();
|
||||
}
|
||||
catch( Exception::ThreadTimedOut& ) { throw; }
|
||||
catch( Exception::CancelEvent& ) { throw; }
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
// 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
|
||||
// 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,
|
||||
|
@ -427,6 +491,8 @@ void Pcsx2App::CleanupMess()
|
|||
|
||||
while( wxGetLocale() != NULL )
|
||||
delete wxGetLocale();
|
||||
|
||||
pxDoAssert = pxAssertImpl_LogIt;
|
||||
}
|
||||
|
||||
Pcsx2App::Pcsx2App()
|
||||
|
@ -441,6 +507,8 @@ Pcsx2App::Pcsx2App()
|
|||
|
||||
Pcsx2App::~Pcsx2App()
|
||||
{
|
||||
pxDoAssert = pxAssertImpl_LogIt;
|
||||
|
||||
// Typically OnExit cleans everything up before we get here, *unless* we cancel
|
||||
// out of program startup in OnInit (return false) -- then remaining cleanup needs
|
||||
// to happen here in the destructor.
|
||||
|
@ -485,6 +553,6 @@ struct CrtDebugBreak
|
|||
}
|
||||
};
|
||||
|
||||
//CrtDebugBreak breakAt( 4327 );
|
||||
//CrtDebugBreak breakAt( 1175 );
|
||||
|
||||
#endif
|
|
@ -53,7 +53,7 @@ ConfigOverrides OverrideOptions;
|
|||
|
||||
static bool HandlePluginError( Exception::PluginError& ex )
|
||||
{
|
||||
if( pxDialogExists( DialogId_CoreSettings ) ) return true;
|
||||
if( pxDialogExists( L"CoreSettings" ) ) return true;
|
||||
|
||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||
_("\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";
|
||||
|
||||
// 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 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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -130,54 +118,69 @@ void Pcsx2App::OnCoreThreadStatus( wxCommandEvent& evt )
|
|||
|
||||
void Pcsx2App::OnOpenModalDialog( wxCommandEvent& evt )
|
||||
{
|
||||
using namespace Dialogs;
|
||||
pxAssertDev( !evt.GetString().IsEmpty(), wxNullChar );
|
||||
|
||||
MsgboxEventResult& evtres( *((MsgboxEventResult*)evt.GetClientData()) );
|
||||
switch( evt.GetId() )
|
||||
MsgboxEventResult* evtres = (MsgboxEventResult*)evt.GetClientData();
|
||||
|
||||
wxWindowID result = IssueModalDialog( evt.GetString() );
|
||||
|
||||
if( evtres != NULL )
|
||||
{
|
||||
case DialogId_CoreSettings:
|
||||
{
|
||||
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->result = result;
|
||||
evtres->WaitForMe.Post();
|
||||
}
|
||||
|
||||
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 );
|
||||
|
@ -227,15 +230,14 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::BiosLoadFailed& ex )
|
||||
{
|
||||
bool result = Dialogs::ExtensibleConfirmation( NULL, ConfButtons().OK().Cancel(),
|
||||
L"PS2 BIOS Error",
|
||||
ex.FormatDisplayMessage() + BIOS_GetMsg_Required() + _("\nPress Ok to go to the BIOS Configuration Panel.")
|
||||
).ShowModal() != wxID_CANCEL;
|
||||
|
||||
if( !result )
|
||||
wxDialogWithHelpers dialog( NULL, _("PS2 BIOS Error"), wxVERTICAL );
|
||||
dialog += dialog.Heading( ex.FormatDisplayMessage() + BIOS_GetMsg_Required() + _("\nPress Ok to go to the BIOS Configuration Panel.") );
|
||||
dialog += new ModalButtonPanel( &dialog, MsgButtons().OKCancel() );
|
||||
|
||||
if( dialog.ShowModal() == wxID_CANCEL )
|
||||
Console.Warning( "User denied option to re-configure BIOS." );
|
||||
|
||||
if( Dialogs::BiosSelectorDialog().ShowModal() != wxID_CANCEL )
|
||||
if( IssueModalDialog( Dialogs::BiosSelectorDialog::GetNameStatic() ) != wxID_CANCEL )
|
||||
{
|
||||
SysExecute();
|
||||
}
|
||||
|
@ -268,15 +270,22 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
// ----------------------------------------------------------------------------
|
||||
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() );
|
||||
int result = Dialogs::ExtensibleConfirmation( NULL, ConfButtons().Ignore().Cancel().Custom( _("Terminate") ),
|
||||
_("PCSX2 Unresponsive Thread"), ex.FormatDisplayMessage() + L"\n\n" +
|
||||
wxDialogWithHelpers dialog( NULL, _("PCSX2 Unresponsive Thread"), wxVERTICAL );
|
||||
|
||||
dialog += dialog.Heading( ex.FormatDisplayMessage() + L"\n\n" +
|
||||
pxE( ".Popup Error:Thread Deadlock Actions",
|
||||
L"'Ignore' to continue waiting for the thread to respond.\n"
|
||||
L"'Cancel' to attempt to cancel the thread.\n"
|
||||
L"'Terminate' to quit PCSX2 immediately.\n"
|
||||
)
|
||||
).ShowModal();
|
||||
);
|
||||
|
||||
int result = pxIssueConfirmation( dialog, MsgButtons().Ignore().Cancel().Custom( _("Terminate") ) );
|
||||
|
||||
if( result == pxID_CUSTOM )
|
||||
{
|
||||
|
@ -386,14 +395,14 @@ int Pcsx2App::OnExit()
|
|||
// is a matter of programmer preference).
|
||||
MainEmuFrame& Pcsx2App::GetMainFrame() const
|
||||
{
|
||||
pxAssert( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
||||
pxAssert( m_MainFrame != NULL );
|
||||
pxAssume( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
||||
pxAssume( m_MainFrame != NULL );
|
||||
return *m_MainFrame;
|
||||
}
|
||||
|
||||
GSFrame& Pcsx2App::GetGSFrame() const
|
||||
{
|
||||
pxAssert( m_gsFrame != NULL );
|
||||
pxAssume( m_gsFrame != NULL );
|
||||
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*.
|
||||
void Pcsx2App::SysReset()
|
||||
{
|
||||
StateCopy_Clear();
|
||||
|
||||
CoreThread.Reset();
|
||||
CoreThread.ReleaseResumeLock();
|
||||
m_CorePlugins = NULL;
|
||||
|
|
|
@ -176,8 +176,15 @@ ConsoleLogFrame::ColorArray::~ColorArray()
|
|||
|
||||
void ConsoleLogFrame::ColorArray::Create( int fontsize )
|
||||
{
|
||||
const wxFont fixed( fontsize, wxMODERN, wxNORMAL, wxNORMAL );
|
||||
const wxFont fixedB( fontsize, wxMODERN, wxNORMAL, wxBOLD );
|
||||
// pxGetFixedFont selects Andale Mono on Win32, which is nice visually but
|
||||
// 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:
|
||||
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.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& menuAppear (*new wxMenu());
|
||||
wxMenu& menuSources (*new wxMenu());
|
||||
|
|
|
@ -96,10 +96,10 @@ protected:
|
|||
EventListenerBinding<PluginEventType> m_Listener_CorePluginStatus;
|
||||
|
||||
#ifdef __WXMSW__
|
||||
int m_win32_StupidRefreshTricks;
|
||||
int m_win32_LinesPerPage;
|
||||
int m_win32_LinesPerScroll;
|
||||
#endif
|
||||
bool m_IsPaused;
|
||||
bool m_FreezeWrites;
|
||||
|
||||
public:
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <wx/mstream.h>
|
||||
#include <wx/hyperlink.h>
|
||||
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
namespace Dialogs
|
||||
{
|
||||
// Helper class for creating wxStaticText labels which are aligned to center.
|
||||
|
@ -45,11 +47,14 @@ namespace Dialogs
|
|||
// AboutBoxDialog Implementation
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
||||
wxDialogWithHelpers( parent, id, _("About PCSX2"), false ),
|
||||
m_bitmap_dualshock( this, wxID_ANY, wxBitmap( EmbeddedImage<res_Dualshock>().Get() ),
|
||||
wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN )
|
||||
Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent )
|
||||
: wxDialogWithHelpers( parent, _("About PCSX2"), wxVERTICAL )
|
||||
, m_bitmap_dualshock( this, wxID_ANY, wxBitmap( EmbeddedImage<res_Dualshock>().Get() ),
|
||||
wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN
|
||||
)
|
||||
{
|
||||
SetName( GetNameStatic() );
|
||||
|
||||
static const wxString LabelAuthors = fromUTF8(
|
||||
"Developers"
|
||||
"\n\n"
|
||||
|
@ -80,10 +85,6 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
|||
"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!
|
||||
wxBoxSizer& AuthLogoSizer = *new wxBoxSizer( wxHORIZONTAL );
|
||||
|
||||
|
@ -99,18 +100,21 @@ Dialogs::AboutBoxDialog::AboutBoxDialog( wxWindow* parent, int id ):
|
|||
label_auth->Wrap( 340 );
|
||||
label_greets->Wrap( 200 );
|
||||
|
||||
aboutUs.Add( label_auth, pxSizerFlags::StdExpand() );
|
||||
contribs.Add( label_greets, pxSizerFlags::StdExpand() );
|
||||
aboutUs += label_auth | StdExpand();
|
||||
contribs += label_greets | StdExpand();
|
||||
|
||||
AuthLogoSizer.Add( &aboutUs );
|
||||
AuthLogoSizer.AddSpacer( 7 );
|
||||
AuthLogoSizer.Add( &contribs );
|
||||
AuthLogoSizer += aboutUs;
|
||||
AuthLogoSizer += 7;
|
||||
AuthLogoSizer += contribs;
|
||||
|
||||
ContribSizer.AddStretchSpacer( 1 );
|
||||
ContribSizer.Add( &m_bitmap_dualshock, pxSizerFlags::StdSpace() );
|
||||
ContribSizer += m_bitmap_dualshock | StdSpace();
|
||||
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,
|
||||
_("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"
|
||||
) | wxSizerFlags(1).Center().Border( wxALL, 3 );
|
||||
|
||||
*this += ContribSizer | pxSizerFlags::StdExpand();
|
||||
|
||||
*this += new wxButton( this, wxID_OK, L"I've seen enough") | pxSizerFlags::StdCenter();
|
||||
|
||||
Fit();
|
||||
CenterOnScreen();
|
||||
*this += ContribSizer | StdExpand();
|
||||
*this += new wxButton( this, wxID_OK, L"I've seen enough") | StdCenter();
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id )
|
||||
: wxDialogWithHelpers( parent, id, _("PCSX2 Configuration"), true )
|
||||
Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent )
|
||||
: wxDialogWithHelpers( parent, _("PCSX2 Configuration"), true )
|
||||
, m_listbook( *new wxListbook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, s_orient ) )
|
||||
{
|
||||
SetName( GetNameStatic() );
|
||||
|
||||
m_idealWidth = 600;
|
||||
|
||||
m_listbook.SetImageList( &wxGetApp().GetImgList_Config() );
|
||||
|
@ -85,9 +87,6 @@ Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id )
|
|||
|
||||
FindWindow( wxID_APPLY )->Disable();
|
||||
|
||||
Fit();
|
||||
CenterOnScreen();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
// 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
|
||||
|
@ -103,6 +102,8 @@ Dialogs::ConfigurationDialog::ConfigurationDialog( wxWindow* parent, int id )
|
|||
Connect( wxID_APPLY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ConfigurationDialog::OnApply_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
|
||||
// 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();
|
||||
}
|
||||
|
||||
void Dialogs::ConfigurationDialog::OnCloseWindow( wxCloseEvent& evt )
|
||||
{
|
||||
if( !IsModal() ) Destroy();
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
void Dialogs::ConfigurationDialog::OnOk_Click( wxCommandEvent& evt )
|
||||
{
|
||||
if( g_ApplyState.ApplyAll() )
|
||||
|
@ -133,8 +140,6 @@ void Dialogs::ConfigurationDialog::OnOk_Click( wxCommandEvent& evt )
|
|||
FindWindow( wxID_APPLY )->Disable();
|
||||
g_Conf->SettingsTabName = m_labels[m_listbook.GetSelection()];
|
||||
AppSaveSettings();
|
||||
|
||||
Close();
|
||||
evt.Skip();
|
||||
}
|
||||
}
|
||||
|
@ -181,9 +186,11 @@ void Dialogs::ConfigurationDialog::OnScreenshot_Click( wxCommandEvent& evt )
|
|||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
Dialogs::BiosSelectorDialog::BiosSelectorDialog( wxWindow* parent, int id )
|
||||
: wxDialogWithHelpers( parent, id, _("BIOS Selector"), false )
|
||||
Dialogs::BiosSelectorDialog::BiosSelectorDialog( wxWindow* parent )
|
||||
: wxDialogWithHelpers( parent, _("BIOS Selector"), false )
|
||||
{
|
||||
SetName( GetNameStatic() );
|
||||
|
||||
m_idealWidth = 500;
|
||||
|
||||
wxBoxSizer& bleh( *new wxBoxSizer( wxVERTICAL ) );
|
||||
|
|
|
@ -33,7 +33,9 @@ namespace Dialogs
|
|||
|
||||
public:
|
||||
virtual ~ConfigurationDialog() throw();
|
||||
ConfigurationDialog(wxWindow* parent=NULL, int id=DialogId_CoreSettings);
|
||||
ConfigurationDialog(wxWindow* parent=NULL);
|
||||
|
||||
static const wxChar* GetNameStatic() { return L"Dialog:CoreSettings"; }
|
||||
|
||||
protected:
|
||||
template< typename T >
|
||||
|
@ -43,6 +45,8 @@ namespace Dialogs
|
|||
void OnCancel_Click( wxCommandEvent& evt );
|
||||
void OnApply_Click( wxCommandEvent& evt );
|
||||
void OnScreenshot_Click( wxCommandEvent& evt );
|
||||
|
||||
void OnCloseWindow( wxCloseEvent& evt );
|
||||
|
||||
virtual void OnSomethingChanged( wxCommandEvent& evt )
|
||||
{
|
||||
|
@ -54,14 +58,15 @@ namespace Dialogs
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class BiosSelectorDialog : public wxDialogWithHelpers
|
||||
{
|
||||
protected:
|
||||
|
||||
public:
|
||||
virtual ~BiosSelectorDialog() throw() {}
|
||||
BiosSelectorDialog( wxWindow* parent=NULL, int id=DialogId_BiosSelector );
|
||||
BiosSelectorDialog( wxWindow* parent=NULL );
|
||||
|
||||
static const wxChar* GetNameStatic() { return L"Dialog:BiosSelector"; }
|
||||
|
||||
protected:
|
||||
void OnOk_Click( wxCommandEvent& evt );
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
#include "ModalPopups.h"
|
||||
#include "Utilities/StringHelpers.h"
|
||||
|
||||
bool ConfButtons::Allows( wxWindowID id ) const
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
bool MsgButtons::Allows( wxWindowID id ) const
|
||||
{
|
||||
switch( id )
|
||||
{
|
||||
|
@ -63,7 +65,7 @@ static wxString ResultToString( int result )
|
|||
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;
|
||||
|
||||
|
@ -85,7 +87,53 @@ static wxWindowID ParseThatResult( const wxString& src, const ConfButtons& valid
|
|||
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();
|
||||
|
||||
|
@ -112,135 +160,143 @@ wxWindowID Dialogs::IssueConfirmation( ExtensibleConfirmation& confirmDlg, const
|
|||
result = split[0];
|
||||
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( cfg == NULL ) return confirmDlg.ShowModal();
|
||||
|
||||
// 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() )
|
||||
pxCheckBox* DisablerCtrl = NULL;
|
||||
if( cfg != NULL )
|
||||
{
|
||||
cfg->SetPath( L"/PopupDisablers" );
|
||||
cfg->Write( disablerKey, L"disabled," + cfgResult );
|
||||
cfg->SetPath( L"/" );
|
||||
// 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)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Dialogs::ExtensibleConfirmation::ExtensibleConfirmation( wxWindow* parent, const ConfButtons& type, const wxString& title, const wxString& msg )
|
||||
: wxDialogWithHelpers( parent, wxID_ANY, title, false )
|
||||
, m_ExtensibleSizer( *new wxBoxSizer( wxVERTICAL ) )
|
||||
, m_ButtonSizer( *new wxBoxSizer( wxHORIZONTAL ) )
|
||||
ModalButtonPanel::ModalButtonPanel( wxWindow* parent, const MsgButtons& buttons )
|
||||
: wxPanelWithHelpers( parent, wxHORIZONTAL )
|
||||
{
|
||||
m_Buttons = type;
|
||||
m_idealWidth = 500;
|
||||
|
||||
SetSizer( new wxBoxSizer(wxVERTICAL) );
|
||||
|
||||
// Populate the Button Sizer.
|
||||
// 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
|
||||
// of right-justified buttons.
|
||||
|
||||
if( type.HasCustom() )
|
||||
AddCustomButton( pxID_CUSTOM, type.GetCustomLabel() );
|
||||
|
||||
if( buttons.HasCustom() )
|
||||
AddCustomButton( pxID_CUSTOM, buttons.GetCustomLabel() );
|
||||
|
||||
// Order of wxID_RESET and custom button have been picked fairly arbitrarily, since there's
|
||||
// no standard governing those.
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#ifdef __WXGTK__
|
||||
// GTK+ / Linux inverts OK/CANCEL order -- cancel / no first, OK / Yes later. >_<
|
||||
if( type.HasCancel() )
|
||||
if( buttons.HasCancel() )
|
||||
AddActionButton( wxID_CANCEL );
|
||||
|
||||
if( type.HasNo() )
|
||||
if( buttons.HasNo() )
|
||||
{
|
||||
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 );
|
||||
|
||||
if( type.HasYes() )
|
||||
if( buttons.HasYes() )
|
||||
{
|
||||
AddActionButton( wxID_YES );
|
||||
if( type.AllowsToAll() )
|
||||
if( buttons.AllowsToAll() )
|
||||
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") );
|
||||
|
||||
if( type.HasClose() )
|
||||
if( buttons.HasClose() )
|
||||
AddActionButton( wxID_CLOSE );
|
||||
|
||||
#ifndef __WXGTK__
|
||||
if( type.HasNo() || type.HasCancel() ) // Extra space between Affirm and Cancel Actions
|
||||
m_ButtonSizer.Add(0, 0, 1, wxEXPAND, 0);
|
||||
|
||||
if( type.HasNo() )
|
||||
#ifndef __WXGTK__
|
||||
if( buttons.HasNo() )
|
||||
{
|
||||
AddActionButton( wxID_NO );
|
||||
if( type.AllowsToAll() )
|
||||
if( buttons.AllowsToAll() )
|
||||
AddActionButton( wxID_NOTOALL );
|
||||
}
|
||||
|
||||
if( type.HasCancel() )
|
||||
if( buttons.HasIgnore() )
|
||||
AddCustomButton( wxID_IGNORE, _("Ignore") );
|
||||
|
||||
if( buttons.HasCancel() )
|
||||
AddActionButton( wxID_CANCEL );
|
||||
#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();
|
||||
#endif
|
||||
}
|
||||
|
||||
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 );
|
||||
Connect( id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ExtensibleConfirmation::OnActionButtonClicked ) );
|
||||
*this += new wxButton( this, id, label ) | StdButton().Proportion(6);
|
||||
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 );
|
||||
Connect( id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ExtensibleConfirmation::OnActionButtonClicked ) );
|
||||
*this += new wxButton( this, id ) | StdButton().Proportion(6);
|
||||
Connect( id, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( ModalButtonPanel::OnActionButtonClicked ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <wx/file.h>
|
||||
|
||||
using namespace Panels;
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
template< typename T >
|
||||
static T& MakeWizWidget( int pageid, wxWizardPage* src )
|
||||
|
@ -48,8 +49,6 @@ Panels::SettingsDirPickerPanel::SettingsDirPickerPanel( wxWindow* parent ) :
|
|||
), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE
|
||||
), wxSizerFlags().Expand().Border( wxBOTTOM, 6 )
|
||||
);
|
||||
|
||||
//SetSizerAndFit( GetSizer(), false );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -58,24 +57,22 @@ FirstTimeWizard::UsermodePage::UsermodePage( wxWizard* parent ) :
|
|||
{
|
||||
SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||
|
||||
wxPanelWithHelpers* panel = new wxPanelWithHelpers( this, wxVERTICAL );
|
||||
panel->SetIdealWidth( 640 );
|
||||
wxSizer& s_panel( *panel->GetSizer() );
|
||||
wxPanelWithHelpers& panel( *new wxPanelWithHelpers( this, wxVERTICAL ) );
|
||||
panel.SetIdealWidth( 640 );
|
||||
|
||||
m_dirpick_settings = new SettingsDirPickerPanel( panel );
|
||||
m_panel_LangSel = new LanguageSelectionPanel( panel );
|
||||
m_panel_UserSel = new UsermodeSelectionPanel( panel );
|
||||
m_dirpick_settings = new SettingsDirPickerPanel( &panel );
|
||||
m_panel_LangSel = new LanguageSelectionPanel( &panel );
|
||||
m_panel_UserSel = new UsermodeSelectionPanel( &panel );
|
||||
|
||||
(new pxStaticHeading( panel, _("PCSX2 is starting from a new or unknown folder and needs to be configured.") ))
|
||||
->AddTo( s_panel );
|
||||
panel += panel.Heading(_("PCSX2 is starting from a new or unknown folder and needs to be configured."));
|
||||
|
||||
s_panel.Add( m_panel_LangSel, pxSizerFlags::StdCenter() );
|
||||
s_panel.Add( m_panel_UserSel, wxSizerFlags().Expand().Border( wxALL, 8 ) );
|
||||
panel += m_panel_LangSel | StdCenter();
|
||||
panel += m_panel_UserSel | pxExpand.Border( wxALL, 8 );
|
||||
|
||||
s_panel.AddSpacer( 6 );
|
||||
s_panel.Add( m_dirpick_settings, pxSizerFlags::SubGroup() );
|
||||
panel += 6;
|
||||
panel += m_dirpick_settings | SubGroup();
|
||||
|
||||
GetSizer()->Add( panel, wxSizerFlags().Expand() );
|
||||
panel += panel | pxExpand;
|
||||
|
||||
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 ) )
|
||||
{
|
||||
// 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
|
||||
wxBoxSizer& biosSizer( *new wxBoxSizer( wxVERTICAL ) );
|
||||
biosSizer.Add( &m_panel_BiosSel, pxSizerFlags::StdExpand() );
|
||||
m_page_bios.SetSizer( &biosSizer );
|
||||
|
||||
m_page_plugins. SetSizer( new wxBoxSizer( wxVERTICAL ) );
|
||||
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
|
||||
m_page_usermode.SetClientData ( (void*)0 );
|
||||
|
@ -117,8 +113,13 @@ FirstTimeWizard::FirstTimeWizard( wxWindow* parent )
|
|||
m_page_usermode.SetNext ( &m_page_plugins );
|
||||
m_page_plugins.SetNext ( &m_page_bios );
|
||||
|
||||
GetPageAreaSizer()->Add( &m_page_usermode );
|
||||
GetPageAreaSizer()->Add( &m_page_plugins );
|
||||
GetPageAreaSizer() += m_page_usermode;
|
||||
GetPageAreaSizer() += m_page_plugins;
|
||||
|
||||
// this doesn't descent from wxDialogWithHelpers, so we need to explicitly
|
||||
// fit and center it. :(
|
||||
|
||||
Fit();
|
||||
CenterOnScreen();
|
||||
|
||||
Connect( wxEVT_WIZARD_PAGE_CHANGED, wxWizardEventHandler( FirstTimeWizard::OnPageChanged ) );
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
#include "ModalPopups.h"
|
||||
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent )
|
||||
: wxDialogWithHelpers( parent, wxID_ANY, _("Import Existing Settings?"), false )
|
||||
: wxDialogWithHelpers( parent, _("Import Existing Settings?"), wxVERTICAL )
|
||||
{
|
||||
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"\n\n(or press Cancel to select a different settings folder)" )
|
||||
);
|
||||
heading->SetMinSize( wxSize( m_idealWidth-8, wxDefaultCoord ) );
|
||||
|
||||
wxBoxSizer& s_buttons = *new wxBoxSizer( wxHORIZONTAL );
|
||||
wxButton* b_import = new wxButton( this, wxID_ANY, _("Import") );
|
||||
|
@ -37,19 +38,16 @@ Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent )
|
|||
// --------------------------------------------------------------------
|
||||
// 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() );
|
||||
s_buttons.AddSpacer( 16 );
|
||||
s_buttons.Add( b_over, pxSizerFlags::StdButton() );
|
||||
s_buttons.AddSpacer( 16 );
|
||||
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 );
|
||||
*this += 4;
|
||||
*this += heading;
|
||||
*this += 12;
|
||||
*this += &s_buttons | StdCenter();
|
||||
|
||||
Connect( b_import->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ImportSettingsDialog::OnImport_Click) );
|
||||
Connect( b_over->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ImportSettingsDialog::OnOverwrite_Click) );
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
|
||||
using namespace Panels;
|
||||
|
||||
Dialogs::LogOptionsDialog::LogOptionsDialog( wxWindow* parent, int id )
|
||||
: wxDialogWithHelpers( parent, id, _("High Volume Logging"), true )
|
||||
Dialogs::LogOptionsDialog::LogOptionsDialog( wxWindow* parent )
|
||||
: wxDialogWithHelpers( parent, _("Trace Logging"), true )
|
||||
{
|
||||
SetName( GetNameStatic() );
|
||||
|
||||
m_idealWidth = 480;
|
||||
|
||||
wxBoxSizer& mainsizer = *new wxBoxSizer( wxVERTICAL );
|
||||
|
|
|
@ -28,8 +28,11 @@ namespace Dialogs {
|
|||
class LogOptionsDialog: public wxDialogWithHelpers
|
||||
{
|
||||
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:
|
||||
void OnOk_Click( wxCommandEvent& evt );
|
||||
void OnApply_Click( wxCommandEvent& evt );
|
||||
|
|
|
@ -66,7 +66,7 @@ protected:
|
|||
virtual void OnDoubleClicked( wxCommandEvent& evt );
|
||||
};
|
||||
|
||||
class ConfButtons
|
||||
class MsgButtons
|
||||
{
|
||||
protected:
|
||||
BITFIELD32()
|
||||
|
@ -87,29 +87,29 @@ protected:
|
|||
wxString m_CustomLabel;
|
||||
|
||||
public:
|
||||
ConfButtons() : bitset( 0 ) { }
|
||||
MsgButtons() : bitset( 0 ) { }
|
||||
|
||||
ConfButtons& OK() { m_OK = true; return *this; }
|
||||
ConfButtons& Cancel() { m_Cancel = true; return *this; }
|
||||
ConfButtons& Apply() { m_Apply = true; return *this; }
|
||||
ConfButtons& Yes() { m_Yes = true; return *this; }
|
||||
ConfButtons& No() { m_No = true; return *this; }
|
||||
ConfButtons& ToAll() { m_AllowToAll = true; return *this; }
|
||||
MsgButtons& OK() { m_OK = true; return *this; }
|
||||
MsgButtons& Cancel() { m_Cancel = true; return *this; }
|
||||
MsgButtons& Apply() { m_Apply = true; return *this; }
|
||||
MsgButtons& Yes() { m_Yes = true; return *this; }
|
||||
MsgButtons& No() { m_No = true; return *this; }
|
||||
MsgButtons& ToAll() { m_AllowToAll = true; return *this; }
|
||||
|
||||
ConfButtons& Abort() { m_Abort = true; return *this; }
|
||||
ConfButtons& Retry() { m_Retry = true; return *this; }
|
||||
ConfButtons& Ignore() { m_Ignore = true; return *this; }
|
||||
ConfButtons& Reset() { m_Reset = true; return *this; }
|
||||
ConfButtons& Close() { m_Close = true; return *this; }
|
||||
MsgButtons& Abort() { m_Abort = true; return *this; }
|
||||
MsgButtons& Retry() { m_Retry = true; return *this; }
|
||||
MsgButtons& Ignore() { m_Ignore = true; return *this; }
|
||||
MsgButtons& Reset() { m_Reset = true; return *this; }
|
||||
MsgButtons& Close() { m_Close = true; return *this; }
|
||||
|
||||
ConfButtons& Custom( const wxString& label)
|
||||
MsgButtons& Custom( const wxString& label)
|
||||
{
|
||||
m_CustomLabel = label;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConfButtons& OKCancel() { m_OK = m_Cancel = true; return *this; }
|
||||
ConfButtons& YesNo() { m_Yes = m_No = true; return *this; }
|
||||
MsgButtons& OKCancel() { m_OK = m_Cancel = true; return *this; }
|
||||
MsgButtons& YesNo() { m_Yes = m_No = true; return *this; }
|
||||
|
||||
bool HasOK() const { return m_OK; }
|
||||
bool HasCancel() const { return m_Cancel; }
|
||||
|
@ -128,29 +128,45 @@ public:
|
|||
const wxString& GetCustomLabel() const { return m_CustomLabel; }
|
||||
|
||||
bool Allows( wxWindowID id ) const;
|
||||
void SetBestFocus( wxWindow* dialog ) const;
|
||||
void SetBestFocus( wxWindow& dialog ) const;
|
||||
|
||||
bool operator ==( const ConfButtons& right ) const
|
||||
bool operator ==( const MsgButtons& right ) const
|
||||
{
|
||||
return OpEqu( bitset );
|
||||
}
|
||||
|
||||
bool operator !=( const ConfButtons& right ) const
|
||||
bool operator !=( const MsgButtons& right ) const
|
||||
{
|
||||
return !OpEqu( bitset );
|
||||
}
|
||||
};
|
||||
|
||||
class ModalButtonPanel : public wxPanelWithHelpers
|
||||
{
|
||||
public:
|
||||
ModalButtonPanel( wxWindow* window, const MsgButtons& buttons );
|
||||
virtual ~ModalButtonPanel() throw() { }
|
||||
|
||||
virtual void AddActionButton( wxWindowID id );
|
||||
virtual void AddCustomButton( wxWindowID id, const wxString& label );
|
||||
|
||||
virtual void OnActionButtonClicked( wxCommandEvent& evt );
|
||||
};
|
||||
|
||||
namespace Dialogs
|
||||
{
|
||||
class AboutBoxDialog: public wxDialogWithHelpers
|
||||
{
|
||||
public:
|
||||
AboutBoxDialog( wxWindow* parent=NULL, int id=DialogId_About );
|
||||
virtual ~AboutBoxDialog() throw() {}
|
||||
|
||||
protected:
|
||||
//wxStaticBitmap m_bitmap_logo;
|
||||
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;
|
||||
|
||||
public:
|
||||
PickUserModeDialog( wxWindow* parent, int id=wxID_ANY );
|
||||
PickUserModeDialog( wxWindow* parent );
|
||||
virtual ~PickUserModeDialog() throw() {}
|
||||
|
||||
protected:
|
||||
|
@ -180,42 +196,15 @@ namespace Dialogs
|
|||
void OnOverwrite_Click( wxCommandEvent& evt );
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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
|
||||
class AssertionDialog : public wxDialogWithHelpers
|
||||
{
|
||||
protected:
|
||||
wxBoxSizer& m_ExtensibleSizer;
|
||||
wxBoxSizer& m_ButtonSizer;
|
||||
|
||||
ConfButtons m_Buttons;
|
||||
|
||||
public:
|
||||
ExtensibleConfirmation( wxWindow* parent, const ConfButtons& type, const wxString& title, const wxString& msg );
|
||||
virtual ~ExtensibleConfirmation() 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 );
|
||||
AssertionDialog( const wxString& text, const wxString& stacktrace );
|
||||
virtual ~AssertionDialog() throw() {}
|
||||
|
||||
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
Dialogs::PickUserModeDialog::PickUserModeDialog( wxWindow* parent, int id )
|
||||
: wxDialogWithHelpers( parent, id, _("PCSX2 First Time configuration"), false )
|
||||
Dialogs::PickUserModeDialog::PickUserModeDialog( wxWindow* parent )
|
||||
: wxDialogWithHelpers( parent, _("PCSX2 First Time configuration"), wxVERTICAL )
|
||||
{
|
||||
m_panel_usersel = new UsermodeSelectionPanel( this, false );
|
||||
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 += m_panel_langsel | pxSizerFlags::StdCenter();
|
||||
*this += m_panel_usersel | wxSizerFlags().Expand().Border( wxALL, 8 );
|
||||
|
||||
AddOkCancel( *GetSizer() );
|
||||
Fit();
|
||||
CenterOnScreen();
|
||||
|
||||
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.
|
||||
|
|
|
@ -49,8 +49,9 @@ GSPanel::GSPanel( wxWindow* parent )
|
|||
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
|
||||
, m_HideMouseTimer( this )
|
||||
{
|
||||
m_CursorShown = true;
|
||||
|
||||
m_CursorShown = true;
|
||||
m_HasFocus = false;
|
||||
|
||||
if ( !wxWindow::Create(parent, wxID_ANY) )
|
||||
throw Exception::RuntimeError( "GSPanel constructor esplode!!" );
|
||||
|
||||
|
@ -68,6 +69,9 @@ GSPanel::GSPanel( wxWindow* parent )
|
|||
Connect( wxEVT_SIZE, wxSizeEventHandler (GSPanel::OnResize) );
|
||||
Connect( wxEVT_KEY_DOWN, wxKeyEventHandler (GSPanel::OnKeyDown) );
|
||||
|
||||
Connect( wxEVT_SET_FOCUS, wxFocusEventHandler(GSPanel::OnFocus) );
|
||||
Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler(GSPanel::OnFocusLost) );
|
||||
|
||||
Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
||||
Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
||||
Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(GSPanel::OnShowMouse) );
|
||||
|
@ -131,6 +135,7 @@ void GSPanel::DoResize()
|
|||
|
||||
void GSPanel::OnResize(wxSizeEvent& event)
|
||||
{
|
||||
if( IsBeingDeleted() ) return;
|
||||
DoResize();
|
||||
//Console.Error( "Size? %d x %d", GetSize().x, GetSize().y );
|
||||
//event.
|
||||
|
@ -144,12 +149,14 @@ void GSPanel::OnCloseWindow(wxCloseEvent& evt)
|
|||
|
||||
void GSPanel::OnShowMouse( wxMouseEvent& evt )
|
||||
{
|
||||
if( IsBeingDeleted() ) return;
|
||||
evt.Skip();
|
||||
DoShowMouse();
|
||||
}
|
||||
|
||||
void GSPanel::OnHideMouseTimeout( wxTimerEvent& evt )
|
||||
{
|
||||
if( IsBeingDeleted() || !m_HasFocus ) return;
|
||||
if( CoreThread.GetExecutionMode() != SysThreadBase::ExecMode_Opened ) return;
|
||||
|
||||
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 )
|
||||
{
|
||||
|
@ -234,12 +261,18 @@ wxWindow* GSFrame::GetViewport()
|
|||
|
||||
void GSFrame::OnActivate( wxActivateEvent& evt )
|
||||
{
|
||||
if( IsBeingDeleted() ) return;
|
||||
|
||||
evt.Skip();
|
||||
if( wxWindow* gsPanel = FindWindowByName(L"GSPanel") ) gsPanel->SetFocus();
|
||||
}
|
||||
|
||||
void GSFrame::OnMove( wxMoveEvent& evt )
|
||||
{
|
||||
if( IsBeingDeleted() ) return;
|
||||
|
||||
evt.Skip();
|
||||
|
||||
// evt.GetPosition() returns the client area position, not the window frame position.
|
||||
if( !IsMaximized() && IsVisible() )
|
||||
g_Conf->GSWindow.WindowPos = GetScreenPosition();
|
||||
|
|
|
@ -61,11 +61,7 @@ void IniInterface::Flush()
|
|||
IniScopedGroup::IniScopedGroup( IniInterface& mommy, const wxString& group ) :
|
||||
m_mom( mommy )
|
||||
{
|
||||
if( IsDevBuild )
|
||||
{
|
||||
if( wxStringTokenize( group, L"/" ).Count() > 1 )
|
||||
throw Exception::InvalidArgument( "Cannot nest more than one group deep per instance of IniScopedGroup." );
|
||||
}
|
||||
pxAssertDev( wxStringTokenize( group, L"/" ).Count() <= 1, L"Cannot nest more than one group deep per instance of IniScopedGroup." );
|
||||
m_mom.SetPath( group );
|
||||
}
|
||||
|
||||
|
|
|
@ -38,10 +38,9 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen
|
|||
|
||||
if( filenames.GetCount() > 1 )
|
||||
{
|
||||
Dialogs::ExtensibleConfirmation( m_WindowBound, ConfButtons().Cancel(),
|
||||
_("Drag and Drop Error"),
|
||||
_("It is an error to drop multiple files onto a PCSX2 window. One at a time please, thank you.")
|
||||
);
|
||||
wxDialogWithHelpers dialog( m_WindowBound, _("Drag and Drop Error"), wxVERTICAL );
|
||||
dialog += dialog.Heading( _("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;
|
||||
}
|
||||
|
||||
|
@ -69,13 +68,14 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen
|
|||
bool confirmed = true;
|
||||
if( SysHasValidState() )
|
||||
{
|
||||
Dialogs::ExtensibleConfirmation dialog( m_WindowBound, ConfButtons().Reset().Cancel(),
|
||||
_("Confirm PS2 Reset"),
|
||||
wxDialogWithHelpers dialog( m_WindowBound, _("Confirm PS2 Reset"), wxVERTICAL );
|
||||
|
||||
dialog += dialog.Heading(
|
||||
_("You have dropped the following ELF binary into PCSX2:\n\n") +
|
||||
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 )
|
||||
|
@ -111,14 +111,14 @@ bool IsoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filen
|
|||
|
||||
if( SysHasValidState() )
|
||||
{
|
||||
Dialogs::ExtensibleConfirmation dialog( m_WindowBound, ConfButtons().Reset().Cancel().Custom(_("Swap Disc")),
|
||||
_("Confirm PS2 Reset"),
|
||||
_("You have dropped the following ISO image into PCSX2:\n\n") +
|
||||
wxDialogWithHelpers dialog( m_WindowBound, _("Confirm PS2 Reset"), wxVERTICAL );
|
||||
|
||||
dialog += dialog.Heading(_("You have dropped the following ISO image into PCSX2:\n\n") +
|
||||
filenames[0] + L"\n\n" +
|
||||
_("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 )
|
||||
|
|
|
@ -31,6 +31,7 @@ protected:
|
|||
EventListenerBinding<int> m_Listener_SettingsApplied;
|
||||
wxTimer m_HideMouseTimer;
|
||||
bool m_CursorShown;
|
||||
bool m_HasFocus;
|
||||
|
||||
public:
|
||||
GSPanel( wxWindow* parent );
|
||||
|
@ -49,6 +50,8 @@ protected:
|
|||
void OnShowMouse( wxMouseEvent& evt );
|
||||
void OnHideMouseTimeout( wxTimerEvent& evt );
|
||||
void OnKeyDown( wxKeyEvent& evt );
|
||||
void OnFocus( wxFocusEvent& evt );
|
||||
void OnFocusLost( wxFocusEvent& evt );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -28,6 +28,15 @@
|
|||
|
||||
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();
|
||||
|
||||
void MainEmuFrame::SaveEmuOptions()
|
||||
|
@ -41,12 +50,12 @@ void MainEmuFrame::SaveEmuOptions()
|
|||
|
||||
void MainEmuFrame::Menu_ConfigSettings_Click(wxCommandEvent &event)
|
||||
{
|
||||
Dialogs::ConfigurationDialog( this ).ShowModal();
|
||||
AppOpenDialog<ConfigurationDialog>( this );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_SelectBios_Click(wxCommandEvent &event)
|
||||
{
|
||||
Dialogs::BiosSelectorDialog( this ).ShowModal();
|
||||
AppOpenDialog<BiosSelectorDialog>( this );
|
||||
}
|
||||
|
||||
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.
|
||||
// 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" +
|
||||
_("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;
|
||||
}
|
||||
|
||||
|
@ -141,11 +153,9 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
|
|||
|
||||
if( SysHasValidState() )
|
||||
{
|
||||
ExtensibleConfirmation dialog( this, ConfButtons().Yes().Cancel(),
|
||||
_("Confirm PS2 Reset"), GetMsg_ConfirmSysReset()
|
||||
);
|
||||
|
||||
bool confirmed = (IssueConfirmation( dialog, L"BootCdvd:ConfirmReset" ) != wxID_CANCEL);
|
||||
wxDialogWithHelpers dialog( this, _("Confirm PS2 Reset"), wxVERTICAL );
|
||||
dialog += dialog.Heading( GetMsg_ConfirmSysReset() );
|
||||
bool confirmed = (pxIssueConfirmation( dialog, MsgButtons().Yes().Cancel(), L"BootCdvd:ConfirmReset" ) != wxID_CANCEL);
|
||||
|
||||
if( !confirmed )
|
||||
{
|
||||
|
@ -290,7 +300,7 @@ void MainEmuFrame::Menu_Debug_MemoryDump_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)
|
||||
|
@ -316,5 +326,5 @@ void MainEmuFrame::Menu_PrintCDVD_Info(wxCommandEvent &event)
|
|||
|
||||
void MainEmuFrame::Menu_ShowAboutBox(wxCommandEvent &event)
|
||||
{
|
||||
AboutBoxDialog( this, wxID_ANY ).ShowModal();
|
||||
AppOpenDialog<AboutBoxDialog>( this );
|
||||
}
|
||||
|
|
|
@ -15,130 +15,277 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "App.h"
|
||||
#include "Dialogs/ModalPopups.h"
|
||||
|
||||
DEFINE_EVENT_TYPE( pxEVT_MSGBOX );
|
||||
DEFINE_EVENT_TYPE( pxEVT_CallStackBox );
|
||||
DEFINE_EVENT_TYPE( pxEVT_ASSERTION );
|
||||
|
||||
using namespace Threading;
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
// Thread Safety: Must be called from the GUI thread ONLY.
|
||||
static int pxMessageDialog( const wxString& content, const wxString& caption, long flags )
|
||||
// Thread Safety: Must be called from the GUI thread ONLY. Will assert otherwise.
|
||||
//
|
||||
// [TODO] Add support for icons?
|
||||
//
|
||||
static int pxMessageDialog( const wxString& caption, const wxString& content, const MsgButtons& buttons )
|
||||
{
|
||||
if( IsDevBuild && !wxThread::IsMain() )
|
||||
throw Exception::InvalidOperation( "Function must be called by the main GUI thread only." );
|
||||
if( !AffinityAssert_AllowFromMain() ) return wxID_CANCEL;
|
||||
|
||||
// fixme: If the emulator is currently active and is running in fullscreen mode, then we
|
||||
// need to either:
|
||||
// fixme: If the emulator is currently active and is running in exclusive mode (forced
|
||||
// fullscreen), then we need to either:
|
||||
// 1) Exit fullscreen mode before issuing the popup.
|
||||
// 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.
|
||||
|
||||
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.
|
||||
// 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 )
|
||||
class BaseMessageBoxEvent : public wxEvent
|
||||
{
|
||||
if( IsDevBuild && !wxThread::IsMain() )
|
||||
throw Exception::InvalidOperation( "Function must be called by the main GUI thread only." );
|
||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(BaseMessageBoxEvent)
|
||||
|
||||
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
|
||||
// --------------------------------------------------------------------------------------
|
||||
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:
|
||||
MsgboxEventResult& m_Instdata;
|
||||
wxString m_Title;
|
||||
wxString m_Content;
|
||||
long m_Flags;
|
||||
typedef BaseMessageBoxEvent _parent;
|
||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent)
|
||||
|
||||
protected:
|
||||
wxString m_Title;
|
||||
MsgButtons m_Buttons;
|
||||
|
||||
public:
|
||||
pxMessageBoxEvent()
|
||||
: wxEvent( 0, pxEVT_MSGBOX )
|
||||
, m_Instdata( *(MsgboxEventResult*)NULL )
|
||||
, m_Title()
|
||||
, m_Content()
|
||||
pxMessageBoxEvent( int msgtype=pxEVT_MSGBOX )
|
||||
: BaseMessageBoxEvent( msgtype )
|
||||
{
|
||||
m_Flags = 0;
|
||||
}
|
||||
|
||||
pxMessageBoxEvent( MsgboxEventResult& instdata, const wxString& title, const wxString& content, long flags )
|
||||
: wxEvent( 0, pxEVT_MSGBOX )
|
||||
, m_Instdata( instdata )
|
||||
virtual ~pxMessageBoxEvent() throw() { }
|
||||
virtual pxMessageBoxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
|
||||
|
||||
pxMessageBoxEvent( MsgboxEventResult& instdata, const wxString& title, const wxString& content, const MsgButtons& buttons )
|
||||
: BaseMessageBoxEvent( instdata, content )
|
||||
, m_Title( title )
|
||||
, m_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 )
|
||||
: wxEvent( event )
|
||||
, m_Instdata( event.m_Instdata )
|
||||
: BaseMessageBoxEvent( event )
|
||||
, 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.
|
||||
void DoTheDialog()
|
||||
pxMessageBoxEvent& SetInstData( MsgboxEventResult& instdata )
|
||||
{
|
||||
int result;
|
||||
|
||||
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();
|
||||
_parent::SetInstData( instdata );
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual wxEvent *Clone() const { return new pxMessageBoxEvent(*this); }
|
||||
|
||||
private:
|
||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxMessageBoxEvent)
|
||||
protected:
|
||||
virtual int _DoDialog() const
|
||||
{
|
||||
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
|
||||
{
|
||||
// parameters:
|
||||
// flags - messagebox type flags, such as wxOK, wxCANCEL, etc.
|
||||
//
|
||||
static int ThreadedMessageBox( const wxString& content, const wxString& title, long flags, int boxType=pxEVT_MSGBOX )
|
||||
static int ThreadedMessageBox( BaseMessageBoxEvent& evt )
|
||||
{
|
||||
MsgboxEventResult instdat;
|
||||
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
|
||||
// threaded chaos where our thread keeps running while the popup is awaiting input.
|
||||
|
||||
MsgboxEventResult instdat;
|
||||
pxMessageBoxEvent tevt( instdat, title, content, flags );
|
||||
pxMessageBoxEvent tevt( instdat, title, content, buttons );
|
||||
wxGetApp().AddPendingEvent( tevt );
|
||||
instdat.WaitForMe.WaitNoCancel(); // Important! disable cancellation since we're using local stack vars.
|
||||
return instdat.result;
|
||||
}
|
||||
|
||||
void OnEvent( pxMessageBoxEvent& evt )
|
||||
{
|
||||
evt.DoTheDialog();
|
||||
}
|
||||
|
||||
// Pops up an alert Dialog Box with a singular "OK" button.
|
||||
// Always returns false.
|
||||
bool Alert( const wxString& text, const wxString& caption, int icon )
|
||||
{
|
||||
icon |= wxOK;
|
||||
MsgButtons buttons( MsgButtons().OK() );
|
||||
|
||||
if( wxThread::IsMain() )
|
||||
pxMessageDialog( text, caption, icon );
|
||||
pxMessageDialog( caption, text, buttons );
|
||||
else
|
||||
ThreadedMessageBox( text, caption, icon );
|
||||
ThreadedMessageBox( caption, text, buttons );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -146,60 +293,40 @@ namespace Msgbox
|
|||
// true if OK, false if cancel.
|
||||
bool OkCancel( const wxString& text, const wxString& caption, int icon )
|
||||
{
|
||||
icon |= wxOK | wxCANCEL;
|
||||
MsgButtons buttons( MsgButtons().OKCancel() );
|
||||
|
||||
if( wxThread::IsMain() )
|
||||
{
|
||||
return wxID_OK == pxMessageDialog( text, caption, icon );
|
||||
return wxID_OK == pxMessageDialog( caption, text, buttons );
|
||||
}
|
||||
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 )
|
||||
{
|
||||
icon |= wxYES_NO;
|
||||
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 );
|
||||
MsgButtons buttons( MsgButtons().YesNo() );
|
||||
|
||||
if( wxThread::IsMain() )
|
||||
{
|
||||
return pxCallstackDialog( text, caption, buttons );
|
||||
return wxID_YES == pxMessageDialog( caption, text, buttons );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ThreadedMessageBox( text, caption, buttons, pxEVT_CallStackBox );
|
||||
return wxID_YES == ThreadedMessageBox( caption, text, buttons );
|
||||
}
|
||||
}
|
||||
|
||||
int Assertion( const wxString& text, const wxString& stacktrace )
|
||||
{
|
||||
return CallStack( text, stacktrace,
|
||||
L"\nDo you want to stop the program?"
|
||||
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 );
|
||||
pxAssertionEvent tevt( text, stacktrace );
|
||||
return ThreadedMessageBox( tevt );
|
||||
}
|
||||
}
|
||||
|
||||
void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt )
|
||||
{
|
||||
evt.IssueDialog();
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ Panels::BaseAdvancedCpuOptions::BaseAdvancedCpuOptions( wxWindow* parent )
|
|||
|
||||
// Highlight Default Options:
|
||||
|
||||
m_RoundModePanel->SetDefault( 3 );
|
||||
m_ClampModePanel->SetDefault( 1 );
|
||||
m_RoundModePanel->SetDefaultItem( 3 );
|
||||
m_ClampModePanel->SetDefaultItem( 1 );
|
||||
|
||||
// ---------------------------------
|
||||
// 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_RecIOP = &(new pxRadioPanel( this, tbl_CpuTypes_IOP ))->SetDefault( 1 );
|
||||
m_panel_RecEE = &(new pxRadioPanel( this, tbl_CpuTypes_EE ))->SetDefaultItem( 1 );
|
||||
m_panel_RecIOP = &(new pxRadioPanel( this, tbl_CpuTypes_IOP ))->SetDefaultItem( 1 );
|
||||
|
||||
m_panel_RecEE->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."))
|
||||
};
|
||||
|
||||
m_panel_VU0 = &(new pxRadioPanel( this, tbl_CpuTypes_VU )) ->SetDefault( 1 );
|
||||
m_panel_VU1 = &(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 )) ->SetDefaultItem( 1 );
|
||||
|
||||
m_panel_VU0->Realize();
|
||||
m_panel_VU1->Realize();
|
||||
|
@ -233,6 +233,9 @@ void Panels::CpuPanelEE::Apply()
|
|||
|
||||
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 );
|
||||
m_panel_RecEE->SetSelection( (int)recOps.EnableEE );
|
||||
m_panel_RecIOP->SetSelection( (int)recOps.EnableIOP );
|
||||
|
@ -250,6 +253,12 @@ void Panels::CpuPanelVU::Apply()
|
|||
|
||||
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 );
|
||||
if( recOps.UseMicroVU0 )
|
||||
m_panel_VU0->SetSelection( recOps.EnableVU0 ? 1 : 0 );
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "App.h"
|
||||
#include "Plugins.h"
|
||||
#include "SaveState.h"
|
||||
#include "Utilities/ScopedPtr.h"
|
||||
#include "ConfigurationPanels.h"
|
||||
#include "Dialogs/ModalPopups.h"
|
||||
|
@ -309,37 +310,43 @@ void Panels::PluginSelectorPanel::Apply()
|
|||
break;
|
||||
} while( ++pi, pi->shortname != NULL );
|
||||
|
||||
bool isSuspended = false;
|
||||
|
||||
if( pi->shortname != NULL )
|
||||
{
|
||||
if( CoreThread.IsRunning() )
|
||||
{
|
||||
// [TODO] : Post notice that this shuts down existing emulation, and may not safely recover.
|
||||
Dialogs::ExtensibleConfirmation dialog( this, ConfButtons().OK().Cancel(),
|
||||
|
||||
_("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?"
|
||||
)
|
||||
);
|
||||
wxDialogWithHelpers dialog( this, _("Shutdown PS2 virtual machine?"), wxVERTICAL );
|
||||
|
||||
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 )
|
||||
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 )
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
LoadPluginsImmediate();
|
||||
}
|
||||
catch( Exception::PluginError& ex )
|
||||
|
@ -359,6 +366,8 @@ void Panels::PluginSelectorPanel::Apply()
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
if( isSuspended ) CoreThread.Resume();
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::CancelRefresh()
|
||||
|
@ -591,6 +600,7 @@ void Panels::PluginSelectorPanel::EnumThread::ExecuteTaskInThread()
|
|||
{
|
||||
DevCon.WriteLn( "Plugin Enumeration Thread started..." );
|
||||
|
||||
Sleep( 15 ); // give the window some time to paint.
|
||||
YieldToMain();
|
||||
|
||||
for( int curidx=0; curidx < m_master.FileCount(); ++curidx )
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
RecentIsoManager::RecentIsoManager( wxMenu* 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_SettingsApplied ( wxGetApp().Source_SettingsApplied(), EventListener<int>( this, OnSettingsApplied ) )
|
||||
{
|
||||
|
@ -166,7 +166,7 @@ void RecentIsoManager::DoSettingsLoadSave( IniInterface& ini )
|
|||
{
|
||||
RemoveAllFromMenu();
|
||||
|
||||
m_MaxLength = g_Conf->RecentFileCount;
|
||||
m_MaxLength = g_Conf->RecentIsoCount;
|
||||
IniScopedGroup groupie( ini, L"RecentIso" );
|
||||
for( uint i=0; i<m_MaxLength; ++i )
|
||||
{
|
||||
|
|
|
@ -141,7 +141,7 @@ const wxChar* __fastcall pxGetTranslation( const wxChar* message )
|
|||
if( wxStrlen( message ) > 96 )
|
||||
{
|
||||
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 );
|
||||
|
|
|
@ -31,7 +31,6 @@ void __evt_fastcall pxLogTextCtrl::OnCoreThreadStatusChanged( void* obj, wxComma
|
|||
|
||||
if( mframe->HasWriteLock() ) return;
|
||||
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||
mframe->m_win32_StupidRefreshTricks = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -45,7 +44,6 @@ void __evt_fastcall pxLogTextCtrl::OnCorePluginStatusChanged( void* obj, PluginE
|
|||
|
||||
if( mframe->HasWriteLock() ) return;
|
||||
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||
mframe->m_win32_StupidRefreshTricks = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -58,10 +56,11 @@ pxLogTextCtrl::pxLogTextCtrl( wxWindow* parent )
|
|||
, m_Listener_CorePluginStatus ( wxGetApp().Source_CorePluginStatus(), EventListener<PluginEventType> ( this, OnCorePluginStatusChanged ) )
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
m_win32_StupidRefreshTricks = 0;
|
||||
m_win32_LinesPerScroll = 10;
|
||||
m_win32_LinesPerScroll = 10;
|
||||
m_win32_LinesPerPage = 0;
|
||||
#endif
|
||||
m_FreezeWrites = false;
|
||||
m_IsPaused = false;
|
||||
m_FreezeWrites = false;
|
||||
|
||||
Connect( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEventHandler(pxLogTextCtrl::OnThumbTrack) );
|
||||
Connect( wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEventHandler(pxLogTextCtrl::OnThumbRelease) );
|
||||
|
@ -85,14 +84,12 @@ void pxLogTextCtrl::OnResize( wxSizeEvent& evt )
|
|||
int fonty;
|
||||
GetTextExtent( L"blaH yeah", NULL, &fonty );
|
||||
m_win32_LinesPerPage = (ctrly / fonty) + 1;
|
||||
m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.25;
|
||||
m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.40;
|
||||
#endif
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
bool m_IsPaused = false;
|
||||
|
||||
void pxLogTextCtrl::OnThumbTrack(wxScrollWinEvent& evt)
|
||||
{
|
||||
//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
|
||||
// log aligns itself nicely when we pause emulation or when errors occur.
|
||||
|
||||
//m_win32_StupidRefreshTricks += lines;
|
||||
//if( m_win32_StupidRefreshTricks > m_win32_LinesPerScroll )
|
||||
{
|
||||
wxTextPos showpos = XYToPosition( 1, GetNumberOfLines()-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
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1847,6 +1847,10 @@
|
|||
RelativePath="..\..\gui\AdvancedDialog.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Dialogs\AssertionDialog.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Dialogs\ConfigurationDialog.cpp"
|
||||
>
|
||||
|
|
|
@ -25,7 +25,8 @@ void StreamException_ThrowFromErrno( const wxString& streamname, errno_t errcode
|
|||
switch( errcode )
|
||||
{
|
||||
case EINVAL:
|
||||
throw Exception::InvalidArgument( "Invalid argument" );
|
||||
pxFailDev( L"Invalid argument" );
|
||||
throw Exception::Stream( streamname, "Invalid argument" );
|
||||
|
||||
case EACCES: // Access denied!
|
||||
throw Exception::AccessDenied( streamname );
|
||||
|
@ -75,7 +76,7 @@ void StreamException_ThrowLastError( const wxString& streamname, HANDLE result )
|
|||
throw Exception::AccessDenied( streamname );
|
||||
|
||||
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:
|
||||
throw Exception::AccessDenied( streamname, "Sharing violation" );
|
||||
|
|
|
@ -99,7 +99,7 @@ public:
|
|||
protected:
|
||||
void ExecuteTaskInThread()
|
||||
{
|
||||
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
|
||||
::SetThreadPriority( ::GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL );
|
||||
if( m_outpipe == INVALID_HANDLE_VALUE ) return;
|
||||
|
||||
try
|
||||
|
@ -112,7 +112,7 @@ protected:
|
|||
if( !ReadFile(m_outpipe, s8_Buf, sizeof(s8_Buf)-1, &u32_Read, NULL) )
|
||||
{
|
||||
DWORD result = GetLastError();
|
||||
if( result == ERROR_HANDLE_EOF ) break;
|
||||
if( result == ERROR_HANDLE_EOF || result == ERROR_BROKEN_PIPE ) break;
|
||||
if( result == ERROR_IO_PENDING )
|
||||
{
|
||||
Yield( 10 );
|
||||
|
@ -172,6 +172,10 @@ class WinPipeRedirection : public PipeRedirectionBase
|
|||
DeclareNoncopyableObject( WinPipeRedirection );
|
||||
|
||||
protected:
|
||||
DWORD m_stdhandle;
|
||||
FILE* m_stdfp;
|
||||
FILE m_stdfp_copy;
|
||||
|
||||
HANDLE m_readpipe;
|
||||
HANDLE m_writepipe;
|
||||
int m_crtFile;
|
||||
|
@ -187,21 +191,25 @@ public:
|
|||
};
|
||||
|
||||
WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
||||
: m_readpipe(INVALID_HANDLE_VALUE)
|
||||
, m_writepipe(INVALID_HANDLE_VALUE)
|
||||
, m_crtFile(-1)
|
||||
, m_fp(NULL)
|
||||
, m_Thread( m_readpipe, (stdstream == stderr) ? Color_Red : Color_Black )
|
||||
: 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
|
||||
{
|
||||
pxAssert( (stdstream == stderr) || (stdstream == stdout) );
|
||||
DWORD stdhandle = ( stdstream == stderr ) ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE;
|
||||
|
||||
if( 0 == CreatePipe( &m_readpipe, &m_writepipe, NULL, 0 ) )
|
||||
throw Exception::Win32Error( "CreatePipe failed." );
|
||||
|
||||
if( 0 == SetStdHandle( stdhandle, m_writepipe ) )
|
||||
if( 0 == SetStdHandle( m_stdhandle, m_writepipe ) )
|
||||
throw Exception::Win32Error( "SetStdHandle failed." );
|
||||
|
||||
// Note: Don't use GetStdHandle to "confirm" the handle.
|
||||
|
@ -222,11 +230,19 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
|||
if( m_fp == NULL )
|
||||
throw Exception::RuntimeError( "_fdopen returned NULL." );
|
||||
|
||||
*stdstream = *m_fp;
|
||||
*m_stdfp = *m_fp; // omg hack. but it works >_<
|
||||
setvbuf( stdstream, NULL, _IONBF, 0 );
|
||||
|
||||
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 )
|
||||
{
|
||||
Cleanup();
|
||||
|
@ -235,6 +251,9 @@ WinPipeRedirection::WinPipeRedirection( FILE* stdstream )
|
|||
}
|
||||
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();
|
||||
throw;
|
||||
}
|
||||
|
@ -247,6 +266,12 @@ WinPipeRedirection::~WinPipeRedirection()
|
|||
|
||||
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:
|
||||
// * 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,
|
||||
|
|
|
@ -495,31 +495,44 @@ static const uint m_recBlockAllocSize =
|
|||
(((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4) * sizeof(BASEBLOCK))
|
||||
+ 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()
|
||||
{
|
||||
// Hardware Requirements Check...
|
||||
|
||||
if ( !( x86caps.hasMultimediaExtensions ) )
|
||||
throw Exception::HardwareDeficiency( "Processor doesn't support MMX" );
|
||||
if ( !x86caps.hasMultimediaExtensions )
|
||||
recThrowHardwareDeficiency( L"MMX" );
|
||||
|
||||
if ( !( x86caps.hasStreamingSIMDExtensions ) )
|
||||
throw Exception::HardwareDeficiency( "Processor doesn't support SSE" );
|
||||
if ( !x86caps.hasStreamingSIMDExtensions )
|
||||
recThrowHardwareDeficiency( L"SSE" );
|
||||
|
||||
if ( !( x86caps.hasStreamingSIMD2Extensions ) )
|
||||
throw Exception::HardwareDeficiency( "Processor doesn't support SSE2" );
|
||||
if ( !x86caps.hasStreamingSIMD2Extensions )
|
||||
recThrowHardwareDeficiency( L"SSE2" );
|
||||
|
||||
if( recMem == NULL )
|
||||
{
|
||||
// Note: the VUrec 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.
|
||||
// It's handy to have a constant base address for the EE recompiler buffer, since it
|
||||
// allows me to key in the address directly in the debugger, and also recognize EE
|
||||
// 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;
|
||||
recMem = (u8*)SysMmapEx( 0x20000000, cachememsize, 0, "recAlloc(R5900)" );
|
||||
}
|
||||
|
||||
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.
|
||||
// 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 );
|
||||
|
||||
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;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
|
||||
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
|
||||
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
|
||||
recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32);
|
||||
recRAMCopy = (u32*)curpos;
|
||||
recRAM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Base / 4) * sizeof(BASEBLOCK);
|
||||
recROM = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom / 4) * sizeof(BASEBLOCK);
|
||||
recROM1 = (BASEBLOCK*)curpos; curpos += (Ps2MemSize::Rom1 / 4) * sizeof(BASEBLOCK);
|
||||
recConstBuf = (u32*)curpos; curpos += RECCONSTBUF_SIZE * sizeof(u32);
|
||||
recRAMCopy = (u32*)curpos;
|
||||
|
||||
if( s_pInstCache == NULL )
|
||||
{
|
||||
|
@ -545,7 +558,7 @@ static void recAlloc()
|
|||
}
|
||||
|
||||
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:
|
||||
|
||||
|
@ -564,11 +577,13 @@ struct ManualPageTracking
|
|||
static __aligned16 u16 manual_page[Ps2MemSize::Base >> 12];
|
||||
static __aligned16 u8 manual_counter[Ps2MemSize::Base >> 12];
|
||||
|
||||
static bool eeRecIsReset = false;
|
||||
static u32 eeRecIsReset = 0;
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
void recResetEE( void )
|
||||
{
|
||||
if( AtomicExchange( eeRecIsReset, true ) ) return;
|
||||
|
||||
Console.WriteLn( Color_StrongBlack, "Issuing EE/iR5900-32 Recompiler Reset" );
|
||||
|
||||
maxrecmem = 0;
|
||||
|
@ -630,7 +645,6 @@ void recResetEE( void )
|
|||
x86FpuState = FPU_STATE;
|
||||
|
||||
branch = 0;
|
||||
eeRecIsReset = true;
|
||||
}
|
||||
|
||||
static void recShutdown( void )
|
||||
|
@ -656,26 +670,21 @@ static jmp_buf m_SetJmp_StateCheck;
|
|||
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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!
|
||||
|
||||
#if PCSX2_SEH
|
||||
try {
|
||||
while( true )
|
||||
{
|
||||
eeRecIsReset = false;
|
||||
g_EEFreezeRegs = true;
|
||||
eeRecIsReset = false;
|
||||
g_EEFreezeRegs = true;
|
||||
|
||||
try {
|
||||
EnterRecompiledCode();
|
||||
}
|
||||
catch( Exception::ForceDispatcherReg& ) { }
|
||||
}
|
||||
try {
|
||||
EnterRecompiledCode();
|
||||
}
|
||||
catch( Exception::ExitRecExecute& ) {}
|
||||
catch( Exception::ForceDispatcherReg& ) { }
|
||||
|
||||
#else
|
||||
|
||||
switch( setjmp( m_SetJmp_StateCheck ) )
|
||||
int oldstate;
|
||||
|
||||
if( !setjmp( m_SetJmp_StateCheck ) )
|
||||
{
|
||||
case 0: // first run, fall through to Dispatcher
|
||||
case SetJmp_Dispatcher:
|
||||
while( true )
|
||||
{
|
||||
int oldstate;
|
||||
eeRecIsReset = false;
|
||||
g_EEFreezeRegs = true;
|
||||
|
||||
// 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 Linux, which cannot have a C++ exception cross the recompiler. Hence the changing
|
||||
// of the cancelstate here!
|
||||
// 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 Linux, which cannot have a C++ exception cross the recompiler. Hence the changing
|
||||
// of the cancelstate here!
|
||||
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
||||
SysCoreThread::Get().StateCheckInThread();
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
||||
|
||||
eeRecIsReset = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
__try {
|
||||
#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;
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
|
||||
EnterRecompiledCode();
|
||||
|
||||
// Generally unreachable code here ...
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldstate );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -858,7 +839,7 @@ static void recExitExecution()
|
|||
#if PCSX2_SEH
|
||||
throw Exception::ExitRecExecute();
|
||||
#else
|
||||
longjmp( m_SetJmp_StateCheck, SetJmp_Exit );
|
||||
longjmp( m_SetJmp_StateCheck, 1 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1319,7 +1300,7 @@ static void __fastcall recRecompile( const u32 startpc )
|
|||
if (dumplog & 4) iDumpRegisters(startpc, 0);
|
||||
#endif
|
||||
|
||||
pxAssert( startpc );
|
||||
pxAssume( startpc );
|
||||
|
||||
// if recPtr reached the mem limit reset whole mem
|
||||
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);
|
||||
|
||||
pxAssert(s_pCurBlockEx);
|
||||
pxAssume(s_pCurBlockEx);
|
||||
|
||||
branch = 0;
|
||||
|
||||
|
@ -1359,7 +1340,7 @@ static void __fastcall recRecompile( const u32 startpc )
|
|||
g_cpuHasConstReg = g_cpuFlushedConstReg = 1;
|
||||
g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff;
|
||||
g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0;
|
||||
pxAssert( g_cpuConstRegs[0].UD[0] == 0 );
|
||||
pxAssume( g_cpuConstRegs[0].UD[0] == 0 );
|
||||
|
||||
_initX86regs();
|
||||
_initXMMregs();
|
||||
|
|
|
@ -67,20 +67,20 @@ const __aligned(32) mVU_Globals mVUglob = {
|
|||
// Micro VU - Main Functions
|
||||
//------------------------------------------------------------------
|
||||
|
||||
microVUt(void) mVUthrowHardwareDeficiency( const wxChar* extFail )
|
||||
microVUt(void) mVUthrowHardwareDeficiency( const wxChar* extFail, int vuIndex )
|
||||
{
|
||||
throw Exception::HardwareDeficiency(
|
||||
L"microVU init error: SSE1 is not available!",
|
||||
wxsFormat(_("%s Extensions not found. microVU requires a host CPU with MMX, SSE, and SSE2 extensions."), L"SSE" )
|
||||
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."), extFail )
|
||||
);
|
||||
}
|
||||
|
||||
// Only run this once per VU! ;)
|
||||
microVUt(void) mVUinit(VURegs* vuRegsPtr, int vuIndex) {
|
||||
|
||||
if(!x86caps.hasMultimediaExtensions) mVUthrowHardwareDeficiency( L"MMX" );
|
||||
if(!x86caps.hasStreamingSIMDExtensions) mVUthrowHardwareDeficiency( L"SSE" );
|
||||
if(!x86caps.hasStreamingSIMD2Extensions) mVUthrowHardwareDeficiency( L"SSE2" );
|
||||
if(!x86caps.hasMultimediaExtensions) mVUthrowHardwareDeficiency( L"MMX", vuIndex );
|
||||
if(!x86caps.hasStreamingSIMDExtensions) mVUthrowHardwareDeficiency( L"SSE", vuIndex );
|
||||
if(!x86caps.hasStreamingSIMD2Extensions) mVUthrowHardwareDeficiency( L"SSE2", vuIndex );
|
||||
|
||||
microVU* mVU = mVUx;
|
||||
memset(&mVU->prog, 0, sizeof(mVU->prog));
|
||||
|
@ -182,17 +182,19 @@ microVUt(void) mVUclear(mV, u32 addr, u32 size) {
|
|||
// Clears program data
|
||||
microVUf(void) mVUclearProg(int progIndex) {
|
||||
microVU* mVU = mVUx;
|
||||
mVUprogI.used = 0;
|
||||
mVUprogI.isDead = 1;
|
||||
mVUprogI.isOld = 1;
|
||||
mVUprogI.frame = mVU->prog.curFrame;
|
||||
for (int j = 0; j <= mVUprogI.ranges.max; j++) {
|
||||
mVUprogI.ranges.range[j][0] = -1; // Set range to
|
||||
mVUprogI.ranges.range[j][1] = -1; // indeterminable status
|
||||
mVUprogI.ranges.total = -1;
|
||||
microProgram& program = mVU->prog.prog[progIndex];
|
||||
|
||||
program.used = 0;
|
||||
program.isDead = 1;
|
||||
program.isOld = 1;
|
||||
program.frame = mVU->prog.curFrame;
|
||||
for (int j = 0; j <= program.ranges.max; j++) {
|
||||
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++) {
|
||||
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 ;)
|
||||
}
|
||||
|
||||
static u32 mvu0_allocated = 0;
|
||||
static u32 mvu1_allocated = 0;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// recMicroVU0
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -331,13 +336,21 @@ recMicroVU0::recMicroVU0() {
|
|||
}
|
||||
|
||||
void recMicroVU0::Allocate() {
|
||||
if( AtomicIncrement( m_AllocCount ) == 0 )
|
||||
mVUinit( &VU0, 0 );
|
||||
if( m_AllocCount == 0 )
|
||||
{
|
||||
++m_AllocCount;
|
||||
if( AtomicExchange( mvu0_allocated, 1 ) == 0 )
|
||||
mVUinit( &VU0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void recMicroVU0::Shutdown() throw() {
|
||||
if( AtomicDecrement( m_AllocCount ) == 0 )
|
||||
mVUclose(µVU0);
|
||||
if( m_AllocCount > 0 )
|
||||
{
|
||||
--m_AllocCount;
|
||||
if( AtomicExchange( mvu0_allocated, 0 ) == 1 )
|
||||
mVUclose(µVU0);
|
||||
}
|
||||
}
|
||||
|
||||
void recMicroVU0::Reset() {
|
||||
|
@ -356,7 +369,7 @@ void recMicroVU0::ExecuteBlock() {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -367,32 +380,35 @@ void recMicroVU0::Vsync() throw() {
|
|||
// --------------------------------------------------------------------------------------
|
||||
// recMicroVU1
|
||||
// --------------------------------------------------------------------------------------
|
||||
recMicroVU1::recMicroVU1()
|
||||
{
|
||||
recMicroVU1::recMicroVU1() {
|
||||
IsInterpreter = false;
|
||||
}
|
||||
|
||||
void recMicroVU1::Allocate()
|
||||
{
|
||||
if( AtomicIncrement( m_AllocCount ) == 0 )
|
||||
mVUinit( &VU1, 1 );
|
||||
void recMicroVU1::Allocate() {
|
||||
if( m_AllocCount == 0 )
|
||||
{
|
||||
++m_AllocCount;
|
||||
if( AtomicExchange( mvu1_allocated, 1 ) == 0 )
|
||||
mVUinit( &VU1, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
void recMicroVU1::Shutdown() throw()
|
||||
{
|
||||
if( AtomicDecrement( m_AllocCount ) == 0 )
|
||||
mVUclose(µVU1);
|
||||
void recMicroVU1::Shutdown() throw() {
|
||||
if( m_AllocCount > 0 )
|
||||
{
|
||||
--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;
|
||||
mVUreset(µVU1);
|
||||
}
|
||||
|
||||
void recMicroVU1::ExecuteBlock()
|
||||
{
|
||||
pxAssert( m_AllocCount ); // please allocate me first! :|
|
||||
void recMicroVU1::ExecuteBlock() {
|
||||
pxAssert( mvu1_allocated ); // please allocate me first! :|
|
||||
|
||||
if ((VU0.VI[REG_VPU_STAT].UL & 0x100) == 0) return;
|
||||
pxAssert( (VU1.VI[REG_TPC].UL&7) == 0 );
|
||||
|
@ -402,8 +418,7 @@ void recMicroVU1::ExecuteBlock()
|
|||
XMMRegisters::Thaw();
|
||||
}
|
||||
|
||||
void recMicroVU1::Clear(u32 addr, u32 size)
|
||||
{
|
||||
void recMicroVU1::Clear(u32 addr, u32 size) {
|
||||
pxAssert( m_AllocCount ); // please allocate me first! :|
|
||||
mVUclear(µVU1, addr, size);
|
||||
}
|
||||
|
|
|
@ -121,8 +121,8 @@ extern const __aligned(32) mVU_Globals mVUglob;
|
|||
// Function/Template Stuff
|
||||
#define mVUx (vuIndex ? µVU1 : µVU0)
|
||||
#define mVUop(opName) static void opName (mP)
|
||||
#define microVUr(aType) __recInline aType
|
||||
#define microVUt(aType) __forceinline aType
|
||||
#define microVUr(aType) static __recInline aType
|
||||
#define microVUt(aType) static __forceinline aType
|
||||
#define microVUx(aType) template<int vuIndex> aType
|
||||
#define microVUf(aType) template<int vuIndex> __forceinline aType
|
||||
|
||||
|
|
Loading…
Reference in New Issue