mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
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:
@@ -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
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user