mirror of https://github.com/PCSX2/pcsx2.git
A big old crapload of UI and thread management changes. Recoded the EventSource/EventListener system to be more C++ and less hacky C. Probably breaks Linux!
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2474 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
c8fa4ffd45
commit
e747337d63
|
@ -275,6 +275,10 @@
|
|||
RelativePath="..\..\src\Utilities\vssprintf.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\Utilities\wxAppWithHelpers.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\Utilities\wxGuiTools.cpp"
|
||||
>
|
||||
|
@ -497,6 +501,10 @@
|
|||
RelativePath="..\..\include\Utilities\Path.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\PersistentThread.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\Utilities\PrecompiledHeader.h"
|
||||
>
|
||||
|
@ -533,6 +541,10 @@
|
|||
RelativePath="..\..\include\Utilities\win_memzero.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\wxAppWithHelpers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\wxBaseTools.h"
|
||||
>
|
||||
|
|
|
@ -18,63 +18,17 @@
|
|||
#include <list>
|
||||
#include "Threading.h"
|
||||
|
||||
class wxCommandEvent;
|
||||
|
||||
// __evt_fastcall : Work-around for a GCC 4.3 compilation bug. The templated FuncType
|
||||
// throws type mismatches if we have a __fastcall qualifier. >_< --air
|
||||
|
||||
#if defined( __GNUC__ ) && (__GNUC__ < 4 ) || ((__GNUC__ == 4) && ( __GNUC_MINOR__ <= 3 ))
|
||||
# define __evt_fastcall
|
||||
#else
|
||||
# define __evt_fastcall __fastcall
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListener< typename EvtType >
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template< typename EvtType >
|
||||
struct EventListener
|
||||
{
|
||||
typedef void __evt_fastcall FuncType( void* object, EvtType& evt );
|
||||
|
||||
void* object;
|
||||
FuncType* OnEvent;
|
||||
|
||||
EventListener( FuncType* fnptr )
|
||||
{
|
||||
object = NULL;
|
||||
OnEvent = fnptr;
|
||||
}
|
||||
|
||||
EventListener( void* objhandle, FuncType* fnptr )
|
||||
{
|
||||
object = objhandle;
|
||||
OnEvent = fnptr;
|
||||
}
|
||||
|
||||
bool operator ==( const EventListener& right ) const
|
||||
{
|
||||
return (object == right.object) && (OnEvent == right.OnEvent);
|
||||
}
|
||||
|
||||
bool operator !=( const EventListener& right ) const
|
||||
{
|
||||
return this->operator ==(right);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventSource< template EvtType >
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template< typename EvtType >
|
||||
template< typename ListenerType >
|
||||
class EventSource
|
||||
{
|
||||
public:
|
||||
typedef EventListener< EvtType > ListenerType;
|
||||
typedef typename std::list< ListenerType > ListenerList;
|
||||
typedef typename ListenerList::iterator Handle;
|
||||
typedef typename ListenerType::EvtParams EvtParams;
|
||||
typedef typename std::list< ListenerType* > ListenerList;
|
||||
typedef typename ListenerList::iterator ListenerIterator;
|
||||
|
||||
protected:
|
||||
typedef typename ListenerList::const_iterator ConstIterator;
|
||||
|
@ -90,27 +44,34 @@ protected:
|
|||
Threading::Mutex m_listeners_lock;
|
||||
|
||||
public:
|
||||
EventSource() : m_cache_valid( false )
|
||||
EventSource()
|
||||
{
|
||||
m_cache_valid = false;
|
||||
}
|
||||
|
||||
virtual ~EventSource() throw() {}
|
||||
|
||||
virtual void Remove( const ListenerType& listener );
|
||||
virtual void Remove( const Handle& listenerHandle );
|
||||
virtual ListenerIterator Add( ListenerType& listener );
|
||||
virtual void Remove( ListenerType& listener );
|
||||
virtual void Remove( const ListenerIterator& listenerHandle );
|
||||
|
||||
void Add( ListenerType* listener )
|
||||
{
|
||||
if( listener == NULL ) return;
|
||||
Add( *listener );
|
||||
}
|
||||
|
||||
void Remove( ListenerType* listener )
|
||||
{
|
||||
if( listener == NULL ) return;
|
||||
Remove( *listener );
|
||||
}
|
||||
|
||||
Handle AddFast( const ListenerType& listener );
|
||||
void Add( void* objhandle, typename ListenerType::FuncType* fnptr );
|
||||
void Remove( void* objhandle, typename ListenerType::FuncType* fnptr );
|
||||
|
||||
// Checks for duplicates before adding the event.
|
||||
virtual void Add( const ListenerType& listener );
|
||||
virtual void RemoveObject( const void* object );
|
||||
void Dispatch( EvtType& evt );
|
||||
void Dispatch( const EvtParams& params );
|
||||
|
||||
protected:
|
||||
virtual Handle _AddFast_without_lock( const ListenerType& listener );
|
||||
inline void _DispatchRaw( ConstIterator iter, const ConstIterator& iend, EvtType& evt );
|
||||
virtual ListenerIterator _AddFast_without_lock( ListenerType& listener );
|
||||
virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -118,25 +79,26 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// Encapsulated event listener binding, provides the "benefits" of object unwinding.
|
||||
//
|
||||
template< typename EvtType >
|
||||
template< typename ListenerType >
|
||||
class EventListenerBinding
|
||||
{
|
||||
public:
|
||||
typedef typename EventSource<EvtType>::ListenerType ListenerHandle;
|
||||
typedef typename EventSource<EvtType>::Handle ConstIterator;
|
||||
typedef typename EventSource<ListenerType> EventSourceType;
|
||||
typedef typename EventSource<ListenerType>::ListenerIterator ListenerIterator;
|
||||
|
||||
protected:
|
||||
EventSource<EvtType>& m_source;
|
||||
const ListenerHandle m_listener;
|
||||
ConstIterator m_iter;
|
||||
bool m_attached;
|
||||
EventSourceType& m_source;
|
||||
const ListenerType m_listener;
|
||||
ListenerIterator m_iter;
|
||||
bool m_attached;
|
||||
|
||||
public:
|
||||
EventListenerBinding( EventSource<EvtType>& source, const ListenerHandle& listener, bool autoAttach=true )
|
||||
EventListenerBinding( EventSourceType& source, ListenerType& listener, bool autoAttach=true )
|
||||
: m_source( source )
|
||||
, m_listener( listener )
|
||||
, m_attached( false )
|
||||
{
|
||||
m_attached = false;
|
||||
|
||||
// If you want to assert on null pointers, you'll need to do the check yourself. There's
|
||||
// too many cases where silently ignoring null pointers is the desired behavior.
|
||||
//if( !pxAssertDev( listener.OnEvent != NULL, "NULL listener callback function." ) ) return;
|
||||
|
@ -158,13 +120,24 @@ public:
|
|||
void Attach()
|
||||
{
|
||||
if( m_attached || (m_listener.OnEvent == NULL) ) return;
|
||||
m_iter = m_source.AddFast( m_listener );
|
||||
m_iter = m_source.Add( m_listener );
|
||||
m_attached = true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef EventSource<wxCommandEvent> CmdEvt_Source;
|
||||
typedef EventListener<wxCommandEvent> CmdEvt_Listener;
|
||||
typedef EventListenerBinding<wxCommandEvent> CmdEvt_ListenerBinding;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventDispatcher
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used as a base interface for EventListeners. It allows the listeners to do
|
||||
// customized dispatching of several event types into "user friendly" function overrides.
|
||||
//
|
||||
template< typename EvtParams >
|
||||
class IEventDispatcher
|
||||
{
|
||||
protected:
|
||||
IEventDispatcher() {}
|
||||
|
||||
#define EventSource_ImplementType( tname ) template class EventSource<tname>
|
||||
public:
|
||||
virtual ~IEventDispatcher() throw() {}
|
||||
virtual void DispatchEvent( const EvtParams& params )=0;
|
||||
};
|
||||
|
|
|
@ -17,116 +17,81 @@
|
|||
|
||||
using Threading::ScopedLock;
|
||||
|
||||
template< typename EvtType >
|
||||
class PredicatesAreTheThingsOfNightmares
|
||||
{
|
||||
typedef EventListener< EvtType > ListenerType;
|
||||
|
||||
protected:
|
||||
const void* const m_object_match;
|
||||
|
||||
public:
|
||||
PredicatesAreTheThingsOfNightmares( const void* objmatch ) : m_object_match( objmatch ) { }
|
||||
|
||||
bool operator()( const ListenerType& src ) const
|
||||
{
|
||||
return src.object == m_object_match;
|
||||
}
|
||||
};
|
||||
|
||||
// Checks for duplicates before adding the event.
|
||||
template< typename EvtType >
|
||||
void EventSource<EvtType>::Add( const ListenerType& listener )
|
||||
template< typename ListenerType >
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add( ListenerType& listener )
|
||||
{
|
||||
ScopedLock locker( m_listeners_lock );
|
||||
|
||||
if( !pxAssertDev( listener.OnEvent != NULL, "NULL listener callback function." ) ) return;
|
||||
|
||||
Handle iter = m_listeners.begin();
|
||||
while( iter != m_listeners.end() )
|
||||
// Check for duplicates before adding the event.
|
||||
if( IsDebugBuild )
|
||||
{
|
||||
if( *iter == listener ) return;
|
||||
++iter;
|
||||
ListenerIterator iter = m_listeners.begin();
|
||||
while( iter != m_listeners.end() )
|
||||
{
|
||||
if( (*iter) == &listener ) return iter;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
_AddFast_without_lock( listener );
|
||||
return _AddFast_without_lock( listener );
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
void EventSource<EvtType>::Remove( const ListenerType& listener )
|
||||
template< typename ListenerType >
|
||||
void EventSource<ListenerType>::Remove( ListenerType& listener )
|
||||
{
|
||||
ScopedLock locker( m_listeners_lock );
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove( listener );
|
||||
m_listeners.remove( &listener );
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
void EventSource<EvtType>::Remove( const Handle& listenerHandle )
|
||||
template< typename ListenerType >
|
||||
void EventSource<ListenerType>::Remove( const ListenerIterator& listenerHandle )
|
||||
{
|
||||
ScopedLock locker( m_listeners_lock );
|
||||
m_cache_valid = false;
|
||||
m_listeners.erase( listenerHandle );
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
typename EventSource<EvtType>::Handle EventSource<EvtType>::AddFast( const ListenerType& listener )
|
||||
{
|
||||
ScopedLock locker( m_listeners_lock );
|
||||
return _AddFast_without_lock( listener );
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
typename EventSource<EvtType>::Handle EventSource<EvtType>::_AddFast_without_lock( const ListenerType& listener )
|
||||
template< typename ListenerType >
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock( ListenerType& listener )
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.push_front( listener );
|
||||
m_listeners.push_front( &listener );
|
||||
return m_listeners.begin();
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
void EventSource<EvtType>::Add( void* objhandle, typename ListenerType::FuncType* fnptr )
|
||||
{
|
||||
Add( ListenerType( objhandle, fnptr ) );
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
void EventSource<EvtType>::Remove( void* objhandle, typename ListenerType::FuncType* fnptr )
|
||||
{
|
||||
Remove( ListenerType( objhandle, fnptr ) );
|
||||
}
|
||||
|
||||
|
||||
// removes all listeners which reference the given object. Use for assuring object deletion.
|
||||
template< typename EvtType >
|
||||
void EventSource<EvtType>::RemoveObject( const void* object )
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove_if( PredicatesAreTheThingsOfNightmares<EvtType>( object ) );
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
__forceinline void EventSource<EvtType>::_DispatchRaw( ConstIterator iter, const ConstIterator& iend, EvtType& evt )
|
||||
template< typename ListenerType >
|
||||
__forceinline void EventSource<ListenerType>::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams )
|
||||
{
|
||||
while( iter != iend )
|
||||
{
|
||||
try
|
||||
{
|
||||
iter->OnEvent( iter->object, evt );
|
||||
try {
|
||||
(*iter)->DispatchEvent( evtparams );
|
||||
}
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
Console.Error( L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage() );
|
||||
if( IsDevBuild ) {
|
||||
pxFailDev( L"Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
else {
|
||||
Console.Error( L"Ignoring runtime error thrown from event listener: " + ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
if( IsDevBuild ) throw;
|
||||
if( IsDevBuild )
|
||||
{
|
||||
ex.DiagMsg() = L"Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
||||
throw;
|
||||
}
|
||||
Console.Error( L"Ignoring non-runtime BaseException thrown from event listener: " + ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
template< typename EvtType >
|
||||
void EventSource<EvtType>::Dispatch( EvtType& evt )
|
||||
template< typename ListenerType >
|
||||
void EventSource<ListenerType>::Dispatch( const EvtParams& evtparams )
|
||||
{
|
||||
if( !m_cache_valid )
|
||||
{
|
||||
|
@ -134,5 +99,6 @@ void EventSource<EvtType>::Dispatch( EvtType& evt )
|
|||
m_cache_valid = true;
|
||||
}
|
||||
|
||||
_DispatchRaw( m_cache_copy.begin(), m_cache_copy.end(), evt );
|
||||
if( m_cache_copy.empty() ) return;
|
||||
_DispatchRaw( m_cache_copy.begin(), m_cache_copy.end(), evtparams );
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ namespace Exception
|
|||
class HardwareDeficiency : public virtual RuntimeError
|
||||
{
|
||||
public:
|
||||
DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, wxLt("Your machine's hardware is incapable of running Pcsx2. Sorry dood.") );
|
||||
DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") );
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
|
|
@ -15,6 +15,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// This macro is actually useful for about any and every possible application of C++
|
||||
// equality operators.
|
||||
#define OpEqu( field ) (field == right.field)
|
||||
|
||||
// Macro used for removing some of the redtape involved in defining bitfield/union helpers.
|
||||
//
|
||||
#define BITFIELD32() \
|
||||
union { \
|
||||
u32 bitset; \
|
||||
struct {
|
||||
|
||||
#define BITFIELD_END }; };
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// RecursionGuard - Basic protection against function recursion
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
@ -39,6 +53,54 @@ public:
|
|||
bool IsReentrant() const { return Counter > 1; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IDeletableObject
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Oh the fruits and joys of multithreaded C++ coding conundrums! This class provides a way
|
||||
// to be deleted from arbitraty threads, or to delete themselves (which is considered unsafe
|
||||
// in C++, though it does typically work). It also gives objects a second recourse for
|
||||
// doing fully virtualized cleanup, something C++ also makes impossible because of how it
|
||||
// implements it's destructor hierarchy.
|
||||
//
|
||||
// To utilize virtual destruction, override DoDeletion() and be sure to invoke the base class
|
||||
// implementation of DoDeletion().
|
||||
//
|
||||
// Assertions:
|
||||
// This class generates an assertion of the destructor is called from anything other than
|
||||
// the main/gui thread.
|
||||
//
|
||||
// Rationale:
|
||||
// wxWidgets provides a pending deletion feature, but it's specific to wxCore (not wxBase)
|
||||
// which means it requires wxApp and all that, which is bad for plugins and the possibility
|
||||
// of linking PCSX2 core against a non-WX gui in the future. It's also not thread safe
|
||||
// (sigh). And, finally, it requires quite a bit of red tape to implement wxObjects because
|
||||
// of the wx-custom runtime type information. So I made my own.
|
||||
//
|
||||
class IDeletableObject
|
||||
{
|
||||
protected:
|
||||
volatile long m_IsBeingDeleted;
|
||||
|
||||
public:
|
||||
IDeletableObject();
|
||||
virtual ~IDeletableObject() throw();
|
||||
|
||||
void DeleteSelf();
|
||||
bool IsBeingDeleted() { return !!m_IsBeingDeleted; }
|
||||
|
||||
// Returns FALSE if the object is already marked for deletion, or TRUE if the app
|
||||
// should schedule the object for deletion. Only schedule if TRUE is returned, otherwise
|
||||
// the object could get deleted twice if two threads try to schedule it at the same time.
|
||||
bool MarkForDeletion();
|
||||
|
||||
protected:
|
||||
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
|
||||
// but if the SysCore is being linked to another front end, you'll need to implement this
|
||||
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
|
||||
// need to implement one yourself (yay?).
|
||||
virtual void DoDeletion();
|
||||
};
|
||||
|
||||
|
||||
enum PageProtectionMode
|
||||
{
|
||||
|
@ -47,11 +109,11 @@ enum PageProtectionMode
|
|||
Protect_ReadWrite
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// HostSys - Namespace housing general system-level implementations relating to loading
|
||||
// plugins and allocating memory. For now, these functions are all accessed via Sys*
|
||||
// versions defined in System.h/cpp.
|
||||
//
|
||||
// --------------------------------------------------------------------------------------
|
||||
// HostSys
|
||||
// --------------------------------------------------------------------------------------
|
||||
// (this namespace name sucks, and is a throw-back to an older attempt to make things cross
|
||||
// platform prior to wxWidgets .. it should prolly be removed -- air)
|
||||
namespace HostSys
|
||||
{
|
||||
// Maps a block of memory for use as a recompiled code buffer.
|
||||
|
@ -74,9 +136,6 @@ namespace HostSys
|
|||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
extern void InitCPUTicks();
|
||||
extern u64 GetTickFrequency();
|
||||
extern u64 GetCPUTicks();
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Threading.h"
|
||||
#include "EventSource.h"
|
||||
|
||||
namespace Threading
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IThread - Interface for the public access to PersistentThread.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Class usage: Can be used for allowing safe nullification of a thread handle. Rather
|
||||
// than being NULL'd, the handle can be mapped to an IThread implementation which acts
|
||||
// as a do-nothing placebo or an assertion generator.
|
||||
//
|
||||
class IThread
|
||||
{
|
||||
DeclareNoncopyableObject(IThread);
|
||||
|
||||
public:
|
||||
IThread() {}
|
||||
virtual ~IThread() throw() {}
|
||||
|
||||
virtual bool IsSelf() const { return false; }
|
||||
virtual bool IsRunning() { return false; }
|
||||
|
||||
virtual void Start() {}
|
||||
virtual void Cancel( bool isBlocking = true ) {}
|
||||
virtual void Block() {}
|
||||
virtual bool Detach() { return false; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ThreadDeleteEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
class EventListener_Thread : public IEventDispatcher<int>
|
||||
{
|
||||
public:
|
||||
typedef int EvtParams;
|
||||
|
||||
protected:
|
||||
PersistentThread* m_thread;
|
||||
|
||||
public:
|
||||
EventListener_Thread()
|
||||
{
|
||||
m_thread = NULL;
|
||||
}
|
||||
|
||||
virtual ~EventListener_Thread() throw() {}
|
||||
|
||||
void SetThread( PersistentThread& thr ) { m_thread = &thr; }
|
||||
void SetThread( PersistentThread* thr ) { m_thread = thr; }
|
||||
|
||||
void DispatchEvent( const int& params )
|
||||
{
|
||||
OnThreadCleanup();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Invoked by the PersistentThread when the thread execution is ending. This is
|
||||
// typically more useful than a delete listener since the extended thread information
|
||||
// provided by virtualized functions/methods will be available.
|
||||
// Important! This event is executed *by the thread*, so care must be taken to ensure
|
||||
// thread sync when necessary (posting messages to the main thread, etc).
|
||||
virtual void OnThreadCleanup()=0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is meant to be a helper for the typical threading model of "start once and
|
||||
// reuse many times." This class incorporates a lot of extra overhead in stopping and
|
||||
// starting threads, but in turn provides most of the basic thread-safety and event-handling
|
||||
// functionality needed for a threaded operation. In practice this model is usually an
|
||||
// ideal one for efficiency since Operating Systems themselves typically subscribe to a
|
||||
// design where sleeping, suspending, and resuming threads is very efficient, but starting
|
||||
// new threads has quite a bit of overhead.
|
||||
//
|
||||
// To use this as a base class for your threaded procedure, overload the following virtual
|
||||
// methods:
|
||||
// void OnStart();
|
||||
// void ExecuteTaskInThread();
|
||||
// void OnCleanupInThread();
|
||||
//
|
||||
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
||||
// m_sem_event internally to post/receive events for the thread (make a public accessor for
|
||||
// it in your derived class if your thread utilizes the post).
|
||||
//
|
||||
// Notes:
|
||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||
// no dependency options for ensuring correct static var initializations). Use heap
|
||||
// allocation to create thread objects instead.
|
||||
//
|
||||
class PersistentThread : public virtual IThread
|
||||
{
|
||||
DeclareNoncopyableObject(PersistentThread);
|
||||
|
||||
friend void pxYield( int ms );
|
||||
|
||||
protected:
|
||||
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_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.
|
||||
|
||||
volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid
|
||||
volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
||||
|
||||
// exception handle, set non-NULL if the thread terminated with an exception
|
||||
// Use RethrowException() to re-throw the exception using its original exception type.
|
||||
ScopedPtr<Exception::BaseException> m_except;
|
||||
|
||||
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
|
||||
|
||||
public:
|
||||
virtual ~PersistentThread() throw();
|
||||
PersistentThread();
|
||||
PersistentThread( const char* name );
|
||||
|
||||
pthread_t GetId() const { return m_thread; }
|
||||
|
||||
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;
|
||||
|
||||
void AddListener( EventListener_Thread& evt );
|
||||
void AddListener( EventListener_Thread* evt )
|
||||
{
|
||||
if( evt == NULL ) return;
|
||||
AddListener( *evt );
|
||||
}
|
||||
|
||||
void WaitOnSelf( Semaphore& mutex ) const;
|
||||
void WaitOnSelf( Mutex& mutex ) const;
|
||||
bool WaitOnSelf( Semaphore& mutex, const wxTimeSpan& timeout ) const;
|
||||
bool WaitOnSelf( Mutex& mutex, const wxTimeSpan& timeout ) const;
|
||||
|
||||
bool IsRunning() const;
|
||||
bool IsSelf() const;
|
||||
wxString GetName() const;
|
||||
bool HasPendingException() const { return !!m_except; }
|
||||
|
||||
protected:
|
||||
// Extending classes should always implement your own OnStart(), which is called by
|
||||
// Start() once necessary locks have been obtained. Do not override Start() directly
|
||||
// unless you're really sure that's what you need to do. ;)
|
||||
virtual void OnStart();
|
||||
|
||||
virtual void OnStartInThread();
|
||||
|
||||
// This is called when the thread has been canceled or exits normally. The PersistentThread
|
||||
// automatically binds it to the pthread cleanup routines as soon as the thread starts.
|
||||
virtual void OnCleanupInThread();
|
||||
|
||||
// Implemented by derived class to perform actual threaded task!
|
||||
virtual void ExecuteTaskInThread()=0;
|
||||
|
||||
void TestCancel() const;
|
||||
|
||||
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
|
||||
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
|
||||
// or better yet, disable cancellation of the thread completely with DisableCancellation().
|
||||
//
|
||||
// Parameters:
|
||||
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
|
||||
// depending on operating system/platform). If ms is 0 or unspecified, then a single
|
||||
// timeslice is yielded to other contending threads. If no threads are contending for
|
||||
// time when ms==0, then no yield is done, but cancellation is still tested.
|
||||
void Yield( int ms = 0 )
|
||||
{
|
||||
pxAssert( IsSelf() );
|
||||
Threading::Sleep( ms );
|
||||
TestCancel();
|
||||
}
|
||||
|
||||
void FrankenMutex( Mutex& mutex );
|
||||
|
||||
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 );
|
||||
void _internal_execute();
|
||||
void _try_virtual_invoke( void (PersistentThread::*method)() );
|
||||
void _ThreadCleanup();
|
||||
|
||||
static void* _internal_callback( void* func );
|
||||
static void _pt_callback_cleanup( void* handle );
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseTaskThread
|
||||
// --------------------------------------------------------------------------------------
|
||||
// an abstract base class which provides simple parallel execution of single tasks.
|
||||
//
|
||||
// FIXME: This class is incomplete and untested! Don't use, unless you want to fix it
|
||||
// while you're at it. :D
|
||||
//
|
||||
// Implementation:
|
||||
// To use this class your derived class will need to implement its own Task() function
|
||||
// and also a "StartTask( parameters )" function which suits the need of your task, along
|
||||
// with any local variables your task needs to do its job. You may additionally want to
|
||||
// implement a "GetResult()" function, which would be a combination of WaitForResult()
|
||||
// and a return value of the computational result.
|
||||
//
|
||||
// Thread Safety:
|
||||
// If operating on local variables, you must execute WaitForResult() before leaving the
|
||||
// variable scope -- or alternatively have your StartTask() implementation make full
|
||||
// copies of dependent data. Also, by default PostTask() always assumes the previous
|
||||
// task has completed. If your system can post a new task before the previous one has
|
||||
// completed, then it needs to explicitly call WaitForResult() or provide a mechanism
|
||||
// to cancel the previous task (which is probably more work than it's worth).
|
||||
//
|
||||
// Performance notes:
|
||||
// * Remember that thread creation is generally slow, so you should make your object
|
||||
// instance once early and then feed it tasks repeatedly over the course of program
|
||||
// execution.
|
||||
//
|
||||
// * For threading to be a successful speedup, the task being performed should be as lock
|
||||
// free as possible. For example using STL containers in parallel usually fails to
|
||||
// yield any speedup due to the gratuitous amount of locking that the STL performs
|
||||
// internally.
|
||||
//
|
||||
// * The best application of tasking threads is to divide a large loop over a linear array
|
||||
// into smaller sections. For example, if you have 20,000 items to process, the task
|
||||
// can be divided into two threads of 10,000 items each.
|
||||
//
|
||||
class BaseTaskThread : public PersistentThread
|
||||
{
|
||||
protected:
|
||||
volatile bool m_Done;
|
||||
volatile bool m_TaskPending;
|
||||
Semaphore m_post_TaskComplete;
|
||||
Mutex m_lock_TaskComplete;
|
||||
|
||||
public:
|
||||
virtual ~BaseTaskThread() throw() {}
|
||||
BaseTaskThread() :
|
||||
m_Done( false )
|
||||
, m_TaskPending( false )
|
||||
, m_post_TaskComplete()
|
||||
{
|
||||
}
|
||||
|
||||
void Block();
|
||||
void PostTask();
|
||||
void WaitForResult();
|
||||
|
||||
protected:
|
||||
// Abstract method run when a task has been posted. Implementing classes should do
|
||||
// all your necessary processing work here.
|
||||
virtual void Task()=0;
|
||||
|
||||
virtual void ExecuteTaskInThread();
|
||||
};
|
||||
}
|
|
@ -112,7 +112,7 @@ namespace Exception
|
|||
#if wxUSE_GUI
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ThreadTimedOut Exception
|
||||
// ThreadDeadlock Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This exception is thrown by Semaphore and Mutex Wait/Acquire functions if a blocking wait is
|
||||
// needed due to gui Yield recursion, and the timeout period for deadlocking (usually 3 seconds)
|
||||
|
@ -121,24 +121,24 @@ namespace Exception
|
|||
// * If the user-specified timeout is less than the deadlock timeout.
|
||||
// * If the method is run from a thread *other* than the MainGui thread.
|
||||
//
|
||||
class ThreadTimedOut : public virtual BaseThreadError
|
||||
class ThreadDeadlock : public virtual BaseThreadError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( ThreadTimedOut )
|
||||
DEFINE_EXCEPTION_COPYTORS( ThreadDeadlock )
|
||||
|
||||
explicit ThreadTimedOut( Threading::PersistentThread* _thread=NULL, const char* msg="Blocking action timed out waiting for '%s' (potential thread deadlock)." )
|
||||
explicit ThreadDeadlock( Threading::PersistentThread* _thread=NULL, const char* msg="Blocking action timed out waiting for '%s' (potential thread deadlock)." )
|
||||
{
|
||||
m_thread = _thread;
|
||||
BaseException::InitBaseEx( msg );
|
||||
}
|
||||
|
||||
ThreadTimedOut( Threading::PersistentThread& _thread, const char* msg="Blocking action timed out waiting for '%s' (potential thread deadlock)." )
|
||||
ThreadDeadlock( Threading::PersistentThread& _thread, const char* msg="Blocking action timed out waiting for '%s' (potential thread deadlock)." )
|
||||
{
|
||||
m_thread = &_thread;
|
||||
BaseException::InitBaseEx( msg );
|
||||
}
|
||||
|
||||
ThreadTimedOut( Threading::PersistentThread& _thread, const wxString& msg_diag, const wxString& msg_user )
|
||||
ThreadDeadlock( Threading::PersistentThread& _thread, const wxString& msg_diag, const wxString& msg_user )
|
||||
{
|
||||
m_thread = &_thread;
|
||||
BaseException::InitBaseEx( msg_diag, msg_user );
|
||||
|
@ -310,154 +310,6 @@ namespace Threading
|
|||
virtual bool IsRecursive() const { return true; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IThread - Interface for the public access to PersistentThread.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Class usage: Can be used for allowing safe nullification of a thread handle. Rather
|
||||
// than being NULL'd, the handle can be mapped to an IThread implementation which acts
|
||||
// as a do-nothing placebo or an assertion generator.
|
||||
//
|
||||
class IThread
|
||||
{
|
||||
DeclareNoncopyableObject(IThread);
|
||||
|
||||
public:
|
||||
IThread() {}
|
||||
virtual ~IThread() throw() {}
|
||||
|
||||
virtual bool IsSelf() const { return false; }
|
||||
virtual bool IsRunning() { return false; }
|
||||
|
||||
virtual void Start() {}
|
||||
virtual void Cancel( bool isBlocking = true ) {}
|
||||
virtual void Block() {}
|
||||
virtual bool Detach() { return false; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PersistentThread - Helper class for the basics of starting/managing persistent threads.
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is meant to be a helper for the typical threading model of "start once and
|
||||
// reuse many times." This class incorporates a lot of extra overhead in stopping and
|
||||
// starting threads, but in turn provides most of the basic thread-safety and event-handling
|
||||
// functionality needed for a threaded operation. In practice this model is usually an
|
||||
// ideal one for efficiency since Operating Systems themselves typically subscribe to a
|
||||
// design where sleeping, suspending, and resuming threads is very efficient, but starting
|
||||
// new threads has quite a bit of overhead.
|
||||
//
|
||||
// To use this as a base class for your threaded procedure, overload the following virtual
|
||||
// methods:
|
||||
// void OnStart();
|
||||
// void ExecuteTaskInThread();
|
||||
// void OnCleanupInThread();
|
||||
//
|
||||
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
|
||||
// m_sem_event internally to post/receive events for the thread (make a public accessor for
|
||||
// it in your derived class if your thread utilizes the post).
|
||||
//
|
||||
// Notes:
|
||||
// * Constructing threads as static global vars isn't recommended since it can potentially
|
||||
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
|
||||
// no dependency options for ensuring correct static var initializations). Use heap
|
||||
// allocation to create thread objects instead.
|
||||
//
|
||||
class PersistentThread : public virtual IThread
|
||||
{
|
||||
DeclareNoncopyableObject(PersistentThread);
|
||||
|
||||
friend void pxYield( int ms );
|
||||
|
||||
protected:
|
||||
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_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.
|
||||
|
||||
volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid
|
||||
volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
|
||||
|
||||
// exception handle, set non-NULL if the thread terminated with an exception
|
||||
// Use RethrowException() to re-throw the exception using its original exception type.
|
||||
ScopedPtr<Exception::BaseException> m_except;
|
||||
|
||||
public:
|
||||
virtual ~PersistentThread() throw();
|
||||
PersistentThread();
|
||||
PersistentThread( const char* name );
|
||||
|
||||
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;
|
||||
|
||||
void WaitOnSelf( Semaphore& mutex ) const;
|
||||
void WaitOnSelf( Mutex& mutex ) const;
|
||||
bool WaitOnSelf( Semaphore& mutex, const wxTimeSpan& timeout ) const;
|
||||
bool WaitOnSelf( Mutex& mutex, const wxTimeSpan& timeout ) const;
|
||||
|
||||
bool IsRunning() const;
|
||||
bool IsSelf() const;
|
||||
wxString GetName() const;
|
||||
bool HasPendingException() const { return !!m_except; }
|
||||
|
||||
protected:
|
||||
// Extending classes should always implement your own OnStart(), which is called by
|
||||
// Start() once necessary locks have been obtained. Do not override Start() directly
|
||||
// unless you're really sure that's what you need to do. ;)
|
||||
virtual void OnStart();
|
||||
|
||||
virtual void OnStartInThread();
|
||||
|
||||
// This is called when the thread has been canceled or exits normally. The PersistentThread
|
||||
// automatically binds it to the pthread cleanup routines as soon as the thread starts.
|
||||
virtual void OnCleanupInThread();
|
||||
|
||||
// Implemented by derived class to perform actual threaded task!
|
||||
virtual void ExecuteTaskInThread()=0;
|
||||
|
||||
void TestCancel() const;
|
||||
|
||||
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
|
||||
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
|
||||
// or better yet, disable cancellation of the thread completely with DisableCancellation().
|
||||
//
|
||||
// Parameters:
|
||||
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
|
||||
// depending on operating system/platform). If ms is 0 or unspecified, then a single
|
||||
// timeslice is yielded to other contending threads. If no threads are contending for
|
||||
// time when ms==0, then no yield is done, but cancellation is still tested.
|
||||
void Yield( int ms = 0 )
|
||||
{
|
||||
pxAssert( IsSelf() );
|
||||
Threading::Sleep( ms );
|
||||
TestCancel();
|
||||
}
|
||||
|
||||
void FrankenMutex( Mutex& mutex );
|
||||
|
||||
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 );
|
||||
void _internal_execute();
|
||||
void _try_virtual_invoke( void (PersistentThread::*method)() );
|
||||
void _ThreadCleanup();
|
||||
|
||||
static void* _internal_callback( void* func );
|
||||
static void _pt_callback_cleanup( void* handle );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ScopedLock
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -471,7 +323,7 @@ namespace Threading
|
|||
|
||||
protected:
|
||||
Mutex& m_lock;
|
||||
bool m_IsLocked;
|
||||
bool m_IsLocked;
|
||||
|
||||
public:
|
||||
virtual ~ScopedLock() throw()
|
||||
|
@ -482,8 +334,8 @@ namespace Threading
|
|||
|
||||
ScopedLock( Mutex& locker ) :
|
||||
m_lock( locker )
|
||||
, m_IsLocked( true )
|
||||
{
|
||||
m_IsLocked = true;
|
||||
m_lock.Acquire();
|
||||
}
|
||||
|
||||
|
@ -509,8 +361,8 @@ namespace Threading
|
|||
// Special constructor used by ScopedTryLock
|
||||
ScopedLock( Mutex& locker, bool isTryLock ) :
|
||||
m_lock( locker )
|
||||
, m_IsLocked( isTryLock ? m_lock.TryAcquire() : false )
|
||||
{
|
||||
m_IsLocked = isTryLock ? m_lock.TryAcquire() : false;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -551,71 +403,5 @@ namespace Threading
|
|||
|
||||
bool Failed() const { return !m_IsLocked; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseTaskThread
|
||||
// --------------------------------------------------------------------------------------
|
||||
// an abstract base class which provides simple parallel execution of single tasks.
|
||||
//
|
||||
// FIXME: This class is incomplete and untested! Don't use, unless you want to fix it
|
||||
// while you're at it. :D
|
||||
//
|
||||
// Implementation:
|
||||
// To use this class your derived class will need to implement its own Task() function
|
||||
// and also a "StartTask( parameters )" function which suits the need of your task, along
|
||||
// with any local variables your task needs to do its job. You may additionally want to
|
||||
// implement a "GetResult()" function, which would be a combination of WaitForResult()
|
||||
// and a return value of the computational result.
|
||||
//
|
||||
// Thread Safety:
|
||||
// If operating on local variables, you must execute WaitForResult() before leaving the
|
||||
// variable scope -- or alternatively have your StartTask() implementation make full
|
||||
// copies of dependent data. Also, by default PostTask() always assumes the previous
|
||||
// task has completed. If your system can post a new task before the previous one has
|
||||
// completed, then it needs to explicitly call WaitForResult() or provide a mechanism
|
||||
// to cancel the previous task (which is probably more work than it's worth).
|
||||
//
|
||||
// Performance notes:
|
||||
// * Remember that thread creation is generally slow, so you should make your object
|
||||
// instance once early and then feed it tasks repeatedly over the course of program
|
||||
// execution.
|
||||
//
|
||||
// * For threading to be a successful speedup, the task being performed should be as lock
|
||||
// free as possible. For example using STL containers in parallel usually fails to
|
||||
// yield any speedup due to the gratuitous amount of locking that the STL performs
|
||||
// internally.
|
||||
//
|
||||
// * The best application of tasking threads is to divide a large loop over a linear array
|
||||
// into smaller sections. For example, if you have 20,000 items to process, the task
|
||||
// can be divided into two threads of 10,000 items each.
|
||||
//
|
||||
class BaseTaskThread : public PersistentThread
|
||||
{
|
||||
protected:
|
||||
volatile bool m_Done;
|
||||
volatile bool m_TaskPending;
|
||||
Semaphore m_post_TaskComplete;
|
||||
Mutex m_lock_TaskComplete;
|
||||
|
||||
public:
|
||||
virtual ~BaseTaskThread() throw() {}
|
||||
BaseTaskThread() :
|
||||
m_Done( false )
|
||||
, m_TaskPending( false )
|
||||
, m_post_TaskComplete()
|
||||
{
|
||||
}
|
||||
|
||||
void Block();
|
||||
void PostTask();
|
||||
void WaitForResult();
|
||||
|
||||
protected:
|
||||
// Abstract method run when a task has been posted. Implementing classes should do
|
||||
// all your necessary processing work here.
|
||||
virtual void Task()=0;
|
||||
|
||||
virtual void ExecuteTaskInThread();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,8 @@
|
|||
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include "IniInterface.h"
|
||||
#include "Utilities/Threading.h"
|
||||
#include "Utilities/wxGuiTools.h"
|
||||
#include "Threading.h"
|
||||
#include "wxGuiTools.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
|
@ -29,26 +28,10 @@ class pxMessageBoxEvent;
|
|||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE( pxEvt_Ping, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_MessageBox, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_Assertion, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_DeleteObject, -1 )
|
||||
//DECLARE_EVENT_TYPE( pxEvt_Assertion, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppIniSaver / AppIniLoader
|
||||
// --------------------------------------------------------------------------------------
|
||||
class AppIniSaver : public IniSaver
|
||||
{
|
||||
public:
|
||||
AppIniSaver();
|
||||
virtual ~AppIniSaver() throw() {}
|
||||
};
|
||||
|
||||
class AppIniLoader : public IniLoader
|
||||
{
|
||||
public:
|
||||
AppIniLoader();
|
||||
virtual ~AppIniLoader() throw() {}
|
||||
};
|
||||
|
||||
struct MsgboxEventResult
|
||||
{
|
||||
Semaphore WaitForMe;
|
||||
|
@ -84,7 +67,7 @@ protected:
|
|||
wxString m_CustomLabel;
|
||||
|
||||
public:
|
||||
MsgButtons() : bitset( 0 ) { }
|
||||
MsgButtons() { bitset = 0; }
|
||||
|
||||
MsgButtons& OK() { m_OK = true; return *this; }
|
||||
MsgButtons& Cancel() { m_Cancel = true; return *this; }
|
||||
|
@ -253,6 +236,30 @@ protected:
|
|||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxStuckThreadEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
class pxStuckThreadEvent : public BaseMessageBoxEvent
|
||||
{
|
||||
typedef BaseMessageBoxEvent _parent;
|
||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN( pxStuckThreadEvent )
|
||||
|
||||
protected:
|
||||
Threading::PersistentThread& m_Thread;
|
||||
|
||||
public:
|
||||
virtual ~pxStuckThreadEvent() throw() { }
|
||||
virtual pxStuckThreadEvent *Clone() const { return new pxStuckThreadEvent(*this); }
|
||||
|
||||
pxStuckThreadEvent();
|
||||
pxStuckThreadEvent( PersistentThread& thr );
|
||||
pxStuckThreadEvent( MsgboxEventResult& instdata, PersistentThread& thr );
|
||||
pxStuckThreadEvent( const pxStuckThreadEvent& src);
|
||||
|
||||
protected:
|
||||
virtual int _DoDialog() const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxPingEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -274,33 +281,56 @@ public:
|
|||
Semaphore* GetSemaphore() { return m_PostBack; }
|
||||
};
|
||||
|
||||
typedef void FnType_VoidMethod();
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxAppWithHelpers
|
||||
// --------------------------------------------------------------------------------------
|
||||
class wxAppWithHelpers : public wxApp
|
||||
{
|
||||
typedef wxApp _parent;
|
||||
|
||||
DECLARE_DYNAMIC_CLASS(wxAppWithHelpers)
|
||||
|
||||
protected:
|
||||
std::vector<Semaphore*> m_PingWhenIdle;
|
||||
wxTimer m_PingTimer;
|
||||
std::vector<Semaphore*> m_PingWhenIdle;
|
||||
std::vector<IDeletableObject*> m_DeleteWhenIdle;
|
||||
Threading::Mutex m_DeleteIdleLock;
|
||||
wxTimer m_PingTimer;
|
||||
|
||||
public:
|
||||
wxAppWithHelpers();
|
||||
virtual ~wxAppWithHelpers() {}
|
||||
|
||||
void CleanUp();
|
||||
|
||||
void DeleteObject( IDeletableObject& obj );
|
||||
void DeleteObject( IDeletableObject* obj )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
DeleteObject( *obj );
|
||||
}
|
||||
|
||||
void PostCommand( void* clientData, int evtType, int intParam=0, long longParam=0, const wxString& stringParam=wxEmptyString );
|
||||
void PostCommand( int evtType, int intParam=0, long longParam=0, const wxString& stringParam=wxEmptyString );
|
||||
void PostMethod( FnType_VoidMethod* method );
|
||||
|
||||
void Ping();
|
||||
void PingDispatch( const char* action );
|
||||
|
||||
bool OnInit();
|
||||
//int OnExit();
|
||||
|
||||
protected:
|
||||
void PingDispatcher( const char* action );
|
||||
void DeletionDispatcher();
|
||||
|
||||
void OnIdleEvent( wxIdleEvent& evt );
|
||||
void OnPingEvent( pxPingEvent& evt );
|
||||
void OnPingTimeout( wxTimerEvent& evt );
|
||||
void OnMessageBox( pxMessageBoxEvent& evt );
|
||||
void OnMessageBox( BaseMessageBoxEvent& evt );
|
||||
void OnDeleteObject( wxCommandEvent& evt );
|
||||
};
|
||||
|
||||
namespace Msgbox
|
||||
{
|
||||
extern int ShowModal( BaseMessageBoxEvent& evt );
|
||||
}
|
|
@ -19,5 +19,5 @@
|
|||
|
||||
#include <wx/event.h>
|
||||
|
||||
template class EventSource< wxCommandEvent >;
|
||||
template class EventSource< int >;
|
||||
//template class EventSource< wxCommandEvent >;
|
||||
//template class EventSource< int >;
|
||||
|
|
|
@ -140,7 +140,7 @@ bool Threading::Mutex::TryAcquire()
|
|||
// and messages *if* the lock is performed from the main GUI thread.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadTimedOut - See description of ThreadTimedOut for details
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
void Threading::Mutex::Acquire()
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ void Threading::Mutex::Acquire()
|
|||
else if( _WaitGui_RecursionGuard( "Mutex::Acquire" ) )
|
||||
{
|
||||
if( !AcquireWithoutYield(def_deadlock_timeout) )
|
||||
throw Exception::ThreadTimedOut();
|
||||
throw Exception::ThreadDeadlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -165,7 +165,7 @@ void Threading::Mutex::Acquire()
|
|||
}
|
||||
|
||||
// Exceptions:
|
||||
// ThreadTimedOut - See description of ThreadTimedOut for details
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
|
||||
{
|
||||
|
@ -181,7 +181,7 @@ bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
|
|||
if( timeout > def_deadlock_timeout )
|
||||
{
|
||||
if( AcquireWithoutYield(def_deadlock_timeout) ) return true;
|
||||
throw Exception::ThreadTimedOut();
|
||||
throw Exception::ThreadDeadlock();
|
||||
}
|
||||
return AcquireWithoutYield( timeout );
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
|
|||
}
|
||||
|
||||
// Looks like a potential deadlock; throw an exception!
|
||||
throw Exception::ThreadTimedOut();
|
||||
throw Exception::ThreadDeadlock();
|
||||
|
||||
#else
|
||||
return AcquireWithoutYield();
|
||||
|
@ -215,7 +215,7 @@ bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
|
|||
// Implemented internally as a simple Acquire/Release pair.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadTimedOut - See description of ThreadTimedOut for details
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
void Threading::Mutex::Wait()
|
||||
{
|
||||
|
@ -231,7 +231,7 @@ void Threading::Mutex::Wait()
|
|||
// and the mutex is still locked by another thread.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadTimedOut - See description of ThreadTimedOut for details
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
bool Threading::Mutex::Wait( const wxTimeSpan& timeout )
|
||||
{
|
||||
|
|
|
@ -80,7 +80,7 @@ bool Threading::Semaphore::WaitWithoutYield( const wxTimeSpan& timeout )
|
|||
// called from another thread, no message pumping is performed.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadTimedOut - See description of ThreadTimedOut for details
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
void Threading::Semaphore::Wait()
|
||||
{
|
||||
|
@ -93,7 +93,7 @@ void Threading::Semaphore::Wait()
|
|||
{
|
||||
ScopedBusyCursor hourglass( Cursor_ReallyBusy );
|
||||
if( !WaitWithoutYield(def_yieldgui_interval) ) // default is 4 seconds
|
||||
throw Exception::ThreadTimedOut();
|
||||
throw Exception::ThreadDeadlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -116,7 +116,7 @@ void Threading::Semaphore::Wait()
|
|||
// reached prior to timeout.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadTimedOut - See description of ThreadTimedOut for details
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
bool Threading::Semaphore::Wait( const wxTimeSpan& timeout )
|
||||
{
|
||||
|
@ -131,7 +131,7 @@ bool Threading::Semaphore::Wait( const wxTimeSpan& timeout )
|
|||
if( timeout > def_deadlock_timeout )
|
||||
{
|
||||
if( WaitWithoutYield(def_deadlock_timeout) ) return true;
|
||||
throw Exception::ThreadTimedOut();
|
||||
throw Exception::ThreadDeadlock();
|
||||
}
|
||||
return WaitWithoutYield( timeout );
|
||||
}
|
||||
|
|
|
@ -24,12 +24,15 @@
|
|||
# include <signal.h> // for pthread_kill, which is in pthread.h on w32-pthreads
|
||||
#endif
|
||||
|
||||
#include "Threading.h"
|
||||
#include "PersistentThread.h"
|
||||
#include "wxBaseTools.h"
|
||||
#include "ThreadingInternal.h"
|
||||
#include "EventSource.inl"
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
template class EventSource< EventListener_Thread >;
|
||||
|
||||
// 100ms interval for waitgui (issued from blocking semaphore waits on the main thread,
|
||||
// to avoid gui deadlock).
|
||||
const wxTimeSpan Threading::def_yieldgui_interval( 0, 0, 0, 100 );
|
||||
|
@ -160,7 +163,7 @@ Threading::PersistentThread::~PersistentThread() throw()
|
|||
Threading::Sleep( 1 );
|
||||
Detach();
|
||||
}
|
||||
catch( Exception::ThreadTimedOut& ex )
|
||||
catch( Exception::ThreadDeadlock& ex )
|
||||
{
|
||||
// Windows allows for a thread to be terminated forcefully, but it's not really
|
||||
// a safe thing to do since typically threads are acquiring and releasing locks
|
||||
|
@ -353,6 +356,12 @@ bool Threading::PersistentThread::IsRunning() const
|
|||
return !!m_running;
|
||||
}
|
||||
|
||||
void Threading::PersistentThread::AddListener( EventListener_Thread& evt )
|
||||
{
|
||||
evt.SetThread( this );
|
||||
m_evtsrc_OnDelete.Add( evt );
|
||||
}
|
||||
|
||||
// Throws an exception if the thread encountered one. Uses the BaseException's Rethrow() method,
|
||||
// which ensures the exception type remains consistent. Debuggable stacktraces will be lost, since
|
||||
// the thread will have allowed itself to terminate properly.
|
||||
|
|
|
@ -18,7 +18,16 @@
|
|||
|
||||
DEFINE_EVENT_TYPE( pxEvt_Ping );
|
||||
DEFINE_EVENT_TYPE( pxEvt_MessageBox );
|
||||
DEFINE_EVENT_TYPE( pxEvt_Assertion );
|
||||
DEFINE_EVENT_TYPE( pxEvt_DeleteObject );
|
||||
//DEFINE_EVENT_TYPE( pxEvt_Assertion );
|
||||
|
||||
|
||||
void IDeletableObject::DoDeletion()
|
||||
{
|
||||
wxAppWithHelpers* app = wxDynamicCast( wxApp::GetInstance(), wxAppWithHelpers );
|
||||
pxAssume( app != NULL );
|
||||
app->DeleteObject( *this );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxPingEvent Implementations
|
||||
|
@ -44,6 +53,11 @@ pxPingEvent::pxPingEvent( const pxPingEvent& src )
|
|||
m_PostBack = src.m_PostBack;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxAppWithHelpers Implementation
|
||||
// --------------------------------------------------------------------------------------
|
||||
IMPLEMENT_DYNAMIC_CLASS( wxAppWithHelpers, wxApp )
|
||||
|
||||
void wxAppWithHelpers::OnPingEvent( pxPingEvent& evt )
|
||||
{
|
||||
// Ping events are dispatched during the idle event handler, which ensures
|
||||
|
@ -54,7 +68,13 @@ void wxAppWithHelpers::OnPingEvent( pxPingEvent& evt )
|
|||
m_PingTimer.Start( 200, true );
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::PingDispatch( const char* action )
|
||||
void wxAppWithHelpers::CleanUp()
|
||||
{
|
||||
DeletionDispatcher();
|
||||
_parent::CleanUp();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::PingDispatcher( const char* action )
|
||||
{
|
||||
size_t size = m_PingWhenIdle.size();
|
||||
if( size == 0 ) return;
|
||||
|
@ -69,16 +89,26 @@ void wxAppWithHelpers::PingDispatch( const char* action )
|
|||
m_PingWhenIdle.clear();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::DeletionDispatcher()
|
||||
{
|
||||
ScopedLock lock( m_DeleteIdleLock );
|
||||
|
||||
size_t size = m_DeleteWhenIdle.size();
|
||||
if( size == 0 ) return;
|
||||
|
||||
DbgCon.WriteLn( Color_Gray, "App Idle Delete -> %u objects.", size );
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt )
|
||||
{
|
||||
evt.Skip();
|
||||
m_PingTimer.Stop();
|
||||
PingDispatch( "Idle" );
|
||||
PingDispatcher( "Idle" );
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnPingTimeout( wxTimerEvent& evt )
|
||||
{
|
||||
PingDispatch( "Timeout" );
|
||||
PingDispatcher( "Timeout" );
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::Ping()
|
||||
|
@ -106,21 +136,29 @@ void wxAppWithHelpers::PostCommand( int evtType, int intParam, long longParam, c
|
|||
PostCommand( NULL, evtType, intParam, longParam, stringParam );
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::DeleteObject( IDeletableObject& obj )
|
||||
{
|
||||
pxAssume( obj.IsBeingDeleted() );
|
||||
ScopedLock lock( m_DeleteIdleLock );
|
||||
m_DeleteWhenIdle.push_back( &obj );
|
||||
}
|
||||
|
||||
typedef void (wxEvtHandler::*pxMessageBoxEventFunction)(pxMessageBoxEvent&);
|
||||
typedef void (wxEvtHandler::*BaseMessageBoxEventFunction)(BaseMessageBoxEvent&);
|
||||
typedef void (wxEvtHandler::*pxPingEventFunction)(pxPingEvent&);
|
||||
|
||||
bool wxAppWithHelpers::OnInit()
|
||||
{
|
||||
#define pxMessageBoxEventThing(func) \
|
||||
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxMessageBoxEventFunction, &func )
|
||||
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(BaseMessageBoxEventFunction, &func )
|
||||
|
||||
#define pxPingEventHandler(func) \
|
||||
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxPingEventFunction, &func )
|
||||
|
||||
|
||||
Connect( pxEvt_MessageBox, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) );
|
||||
Connect( pxEvt_Assertion, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) );
|
||||
//Connect( pxEvt_Assertion, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) );
|
||||
Connect( pxEvt_Ping, pxPingEventHandler (wxAppWithHelpers::OnPingEvent) );
|
||||
Connect( pxEvt_DeleteObject, wxCommandEventHandler (wxAppWithHelpers::OnDeleteObject) );
|
||||
Connect( wxEVT_IDLE, wxIdleEventHandler (wxAppWithHelpers::OnIdleEvent) );
|
||||
|
||||
Connect( m_PingTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnPingTimeout) );
|
||||
|
@ -128,11 +166,17 @@ bool wxAppWithHelpers::OnInit()
|
|||
return _parent::OnInit();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnMessageBox( pxMessageBoxEvent& evt )
|
||||
void wxAppWithHelpers::OnMessageBox( BaseMessageBoxEvent& evt )
|
||||
{
|
||||
evt.IssueDialog();
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnDeleteObject( wxCommandEvent& evt )
|
||||
{
|
||||
if( evt.GetClientData() == NULL ) return;
|
||||
delete (IDeletableObject*)evt.GetClientData();
|
||||
}
|
||||
|
||||
wxAppWithHelpers::wxAppWithHelpers()
|
||||
: m_PingTimer( this )
|
||||
{
|
|
@ -17,6 +17,7 @@
|
|||
#include "HashMap.h"
|
||||
#include "wxGuiTools.h"
|
||||
#include "pxStaticText.h"
|
||||
#include "Threading.h"
|
||||
|
||||
#include <wx/cshelp.h>
|
||||
#include <wx/tooltip.h>
|
||||
|
@ -24,6 +25,43 @@
|
|||
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IDeletableObject Implementation
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This code probably deserves a better home. It's general purpose non-GUI code (the single
|
||||
// wxApp/Gui dependency is in wxGuiTools.cpp for now).
|
||||
//
|
||||
bool IDeletableObject::MarkForDeletion()
|
||||
{
|
||||
return !_InterlockedExchange( &m_IsBeingDeleted, true );
|
||||
}
|
||||
|
||||
void IDeletableObject::DeleteSelf()
|
||||
{
|
||||
if( MarkForDeletion() )
|
||||
DoDeletion();
|
||||
}
|
||||
|
||||
IDeletableObject::IDeletableObject()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
// Bleh, this fails because _CrtIsValidHeapPointer calls HeapValidate on the
|
||||
// pointer, but the pointer is a virtual base class, so it's not a valid block. >_<
|
||||
//pxAssertDev( _CrtIsValidHeapPointer( this ), "IDeletableObject types cannot be created on the stack or as temporaries!" );
|
||||
#endif
|
||||
|
||||
m_IsBeingDeleted = false;
|
||||
}
|
||||
|
||||
IDeletableObject::~IDeletableObject() throw()
|
||||
{
|
||||
AffinityAssert_AllowFromMain();
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Creates a text control which is right-justified and has it's minimum width configured to suit
|
||||
// the number of digits requested.
|
||||
wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits )
|
||||
|
|
|
@ -37,19 +37,6 @@ enum PluginsEnum_t
|
|||
PluginId_Mcd
|
||||
};
|
||||
|
||||
// This macro is actually useful for about any and every possible application of C++
|
||||
// equality operators.
|
||||
#define OpEqu( field ) (field == right.field)
|
||||
|
||||
// Macro used for removing some of the redtape involved in defining bitfield/union helpers.
|
||||
//
|
||||
#define BITFIELD32() \
|
||||
union { \
|
||||
u32 bitset; \
|
||||
struct {
|
||||
|
||||
#define BITFIELD_END }; };
|
||||
|
||||
//------------ DEFAULT sseMXCSR VALUES ---------------
|
||||
#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding > DaZ, FtZ, "chop"
|
||||
#define DEFAULT_sseVUMXCSR 0xffc0 //VU rounding > DaZ, FtZ, "chop"
|
||||
|
|
|
@ -292,7 +292,7 @@ protected:
|
|||
// apps or DLLs to reference their own instance of SysMtgsThread (also allowing them
|
||||
// to extend the class and override virtual methods).
|
||||
//
|
||||
SysMtgsThread& GetMTGS();
|
||||
extern SysMtgsThread& GetMTGS();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Generalized GS Functions and Stuff
|
||||
|
|
|
@ -54,7 +54,7 @@ static __forceinline u8* iopPhysMem( u32 addr )
|
|||
return &psxM[addr & 0x1fffff];
|
||||
}
|
||||
|
||||
#define psxSs8(mem) psxS[(mem) & 0xffff]
|
||||
#define psxSs8(mem) psxS[(mem) & 0x00ff]
|
||||
#define psxSs16(mem) (*(s16*)&psxS[(mem) & 0x00ff])
|
||||
#define psxSs32(mem) (*(s32*)&psxS[(mem) & 0x00ff])
|
||||
#define psxSu8(mem) (*(u8*) &psxS[(mem) & 0x00ff])
|
||||
|
|
|
@ -30,12 +30,11 @@ static void SysPageFaultSignalFilter( int signal, siginfo_t *siginfo, void * )
|
|||
// Note: Use of most stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
|
||||
PageFaultInfo pfinfo( (uptr)siginfo->si_addr & ~m_pagemask );
|
||||
Source_PageFault.DispatchException( pfinfo );
|
||||
Source_PageFault.Dispatch( PageFaultInfo( (uptr)siginfo->si_addr & ~m_pagemask ) );
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if( pfinfo.handled ) return;
|
||||
if( Source_PageFault.WasHandled() ) return;
|
||||
|
||||
// Bad mojo! Completely invalid address.
|
||||
// Instigate a trap if we're in a debugger, and if not then do a SIGKILL.
|
||||
|
|
|
@ -565,7 +565,13 @@ void memClearPageAddr(u32 vaddr)
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// PS2 Memory Init / Reset / Shutdown
|
||||
|
||||
static void __evt_fastcall mmap_OnPageFault( void* basemem, PageFaultInfo& info );
|
||||
class mmap_PageFaultHandler : public IEventListener_PageFault
|
||||
{
|
||||
protected:
|
||||
void OnPageFaultEvent( const PageFaultInfo& info, bool& handled );
|
||||
};
|
||||
|
||||
mmap_PageFaultHandler mmap_faultHandler;
|
||||
|
||||
static const uint m_allMemSize =
|
||||
Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2 + Ps2MemSize::ERom +
|
||||
|
@ -590,12 +596,12 @@ void memAlloc()
|
|||
psH = curpos; curpos += Ps2MemSize::Hardware;
|
||||
psS = curpos; //curpos += Ps2MemSize::Scratch;
|
||||
|
||||
Source_PageFault.Add( EventListener<PageFaultInfo>((void*)psM, mmap_OnPageFault) );
|
||||
Source_PageFault.Add( mmap_faultHandler );
|
||||
}
|
||||
|
||||
void memShutdown()
|
||||
{
|
||||
Source_PageFault.Remove( EventListener<PageFaultInfo>((void*)psM, mmap_OnPageFault) );
|
||||
Source_PageFault.Remove( mmap_faultHandler );
|
||||
|
||||
vtlb_free( m_psAllMem, m_allMemSize );
|
||||
m_psAllMem = NULL;
|
||||
|
@ -885,14 +891,14 @@ static __forceinline void mmap_ClearCpuBlock( uint offset )
|
|||
Cpu->Clear( m_PageProtectInfo[rampage].ReverseRamMap, 0x400 );
|
||||
}
|
||||
|
||||
static void __evt_fastcall mmap_OnPageFault( void* basemem, PageFaultInfo& info )
|
||||
void mmap_PageFaultHandler::OnPageFaultEvent( const PageFaultInfo& info, bool& handled )
|
||||
{
|
||||
// get bad virtual address
|
||||
uptr offset = info.addr - (uptr)basemem;
|
||||
uptr offset = info.addr - (uptr)psM;
|
||||
if( offset >= Ps2MemSize::Base ) return;
|
||||
|
||||
mmap_ClearCpuBlock( offset );
|
||||
info.handled = true;
|
||||
handled = true;
|
||||
}
|
||||
|
||||
// Clears all block tracking statuses, manual protection flags, and write protection.
|
||||
|
|
|
@ -748,7 +748,7 @@ PluginManager::PluginManager( const wxString (&folders)[PluginId_Count] )
|
|||
wxsFormat( L"Plugin Test failure, return code: %d", testres ),
|
||||
_( "The plugin reports that your hardware or software/drivers are not supported." )
|
||||
);
|
||||
|
||||
|
||||
pxYield( 2 );
|
||||
|
||||
} while( ++pi, pi->shortname != NULL );
|
||||
|
|
|
@ -44,11 +44,20 @@ static bool StateCopy_ForceClear()
|
|||
state_buffer.Dispose();
|
||||
}
|
||||
|
||||
static void __evt_fastcall StateThread_OnAppStatus( void* thr, AppEventType& stat )
|
||||
class EventListener_AppExiting : public IEventListener_AppStatus
|
||||
{
|
||||
if( (thr == NULL) || (stat != AppStatus_Exiting) ) return;
|
||||
((PersistentThread*)thr)->Cancel();
|
||||
}
|
||||
protected:
|
||||
PersistentThread& m_thread;
|
||||
|
||||
public:
|
||||
EventListener_AppExiting( PersistentThread& thr )
|
||||
: m_thread( thr )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~EventListener_AppExiting() throw() {}
|
||||
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -59,17 +68,17 @@ enum
|
|||
StateThreadAction_UnzipFromDisk,
|
||||
};
|
||||
|
||||
class _BaseStateThread : public PersistentThread
|
||||
class _BaseStateThread : public PersistentThread,
|
||||
public virtual IEventListener_AppStatus,
|
||||
public virtual IDeletableObject
|
||||
{
|
||||
typedef PersistentThread _parent;
|
||||
|
||||
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.
|
||||
// so that the proper state can be restored automatically on completion.
|
||||
bool m_resume_when_done;
|
||||
|
||||
public:
|
||||
|
@ -87,7 +96,6 @@ public:
|
|||
|
||||
protected:
|
||||
_BaseStateThread( const char* name, FnType_OnThreadComplete* onFinished )
|
||||
: m_bind_OnExit( wxGetApp().Source_AppStatus(), EventListener<AppEventType>( this, StateThread_OnAppStatus ) )
|
||||
{
|
||||
Callback_FreezeFinished = onFinished;
|
||||
m_name = L"StateThread::" + fromUTF8(name);
|
||||
|
@ -110,6 +118,14 @@ protected:
|
|||
wxGetApp().PostCommand( this, pxEvt_FreezeThreadFinished, type, m_resume_when_done );
|
||||
}
|
||||
|
||||
void AppStatusEvent_OnExit()
|
||||
{
|
||||
Cancel();
|
||||
|
||||
Pcsx2App& myapp( wxGetApp() );
|
||||
myapp.RemoveListener( *this );
|
||||
myapp.DeleteObject( *this );
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -22,10 +22,34 @@
|
|||
#include "System/PageFaultSource.h"
|
||||
#include "Utilities/EventSource.inl"
|
||||
|
||||
template class EventSource< PageFaultInfo >;
|
||||
template class EventSource< IEventListener_PageFault >;
|
||||
|
||||
SrcType_PageFault Source_PageFault;
|
||||
|
||||
IEventListener_PageFault::IEventListener_PageFault()
|
||||
{
|
||||
Source_PageFault.Add( *this );
|
||||
}
|
||||
|
||||
IEventListener_PageFault::~IEventListener_PageFault() throw()
|
||||
{
|
||||
Source_PageFault.Remove( *this );
|
||||
}
|
||||
|
||||
void SrcType_PageFault::Dispatch( const PageFaultInfo& params )
|
||||
{
|
||||
m_handled = false;
|
||||
_parent::Dispatch( params );
|
||||
}
|
||||
|
||||
void SrcType_PageFault::_DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt )
|
||||
{
|
||||
do {
|
||||
(*iter)->DispatchEvent( evt, m_handled );
|
||||
} while( (++iter != iend) && !m_handled );
|
||||
}
|
||||
|
||||
|
||||
#if _MSC_VER
|
||||
# include "svnrev.h"
|
||||
#endif
|
||||
|
|
|
@ -107,10 +107,10 @@ extern void NTFS_CompressFile( const wxString& file, bool compressStatus=true );
|
|||
|
||||
namespace Msgbox
|
||||
{
|
||||
extern bool Alert( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_EXCLAMATION );
|
||||
extern bool OkCancel( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=0 );
|
||||
extern bool YesNo( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_QUESTION );
|
||||
extern bool Alert( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_EXCLAMATION );
|
||||
extern bool OkCancel( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=0 );
|
||||
extern bool YesNo( const wxString& text, const wxString& caption=L"PCSX2 Message", int icon=wxICON_QUESTION );
|
||||
|
||||
extern int Assertion( const wxString& text, const wxString& stacktrace );
|
||||
extern int Assertion( const wxString& text, const wxString& stacktrace );
|
||||
}
|
||||
|
||||
|
|
|
@ -26,38 +26,58 @@
|
|||
struct PageFaultInfo
|
||||
{
|
||||
uptr addr;
|
||||
bool handled;
|
||||
|
||||
PageFaultInfo( uptr address )
|
||||
{
|
||||
addr = address;
|
||||
handled = false;
|
||||
}
|
||||
};
|
||||
|
||||
class SrcType_PageFault : public EventSource<PageFaultInfo>
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventListener_PageFault
|
||||
// --------------------------------------------------------------------------------------
|
||||
class IEventListener_PageFault : public IEventDispatcher<PageFaultInfo>
|
||||
{
|
||||
public:
|
||||
typedef PageFaultInfo EvtParams;
|
||||
|
||||
public:
|
||||
IEventListener_PageFault();
|
||||
virtual ~IEventListener_PageFault() throw();
|
||||
|
||||
virtual void DispatchEvent( const PageFaultInfo& evtinfo, bool& handled )
|
||||
{
|
||||
OnPageFaultEvent( evtinfo, handled );
|
||||
}
|
||||
|
||||
virtual void DispatchEvent( const PageFaultInfo& evtinfo )
|
||||
{
|
||||
pxFailRel( "Don't call me, damnit. Use DispatchException instead." );
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void OnPageFaultEvent( const PageFaultInfo& evtinfo, bool& handled ) {}
|
||||
};
|
||||
|
||||
class SrcType_PageFault : public EventSource<IEventListener_PageFault>
|
||||
{
|
||||
protected:
|
||||
typedef EventSource<IEventListener_PageFault> _parent;
|
||||
|
||||
protected:
|
||||
bool m_handled;
|
||||
|
||||
public:
|
||||
SrcType_PageFault() {}
|
||||
virtual ~SrcType_PageFault() throw() { }
|
||||
|
||||
void DispatchException( PageFaultInfo& evt )
|
||||
{
|
||||
if( m_listeners.empty() ) return;
|
||||
bool WasHandled() const { return m_handled; }
|
||||
virtual void Dispatch( const PageFaultInfo& params );
|
||||
|
||||
ConstIterator iter( m_listeners.begin() );
|
||||
const ConstIterator iend( m_listeners.end() );
|
||||
|
||||
do {
|
||||
iter->OnEvent( iter->object, evt );
|
||||
} while( (++iter != iend) && !evt.handled );
|
||||
}
|
||||
protected:
|
||||
virtual void _DispatchRaw( ListenerIterator iter, const ListenerIterator& iend, const PageFaultInfo& evt );
|
||||
};
|
||||
|
||||
extern SrcType_PageFault Source_PageFault;
|
||||
|
||||
extern void InstallSignalHandler();
|
||||
|
||||
#ifdef __LINUX__
|
||||
|
||||
# define PCSX2_PAGEFAULT_PROTECT
|
||||
|
@ -65,8 +85,8 @@ extern void InstallSignalHandler();
|
|||
|
||||
#elif defined( _WIN32 )
|
||||
|
||||
struct _EXCEPTION_POINTERS;
|
||||
extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
|
||||
struct _EXCEPTION_POINTERS;
|
||||
extern int SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* eps);
|
||||
|
||||
# define PCSX2_PAGEFAULT_PROTECT __try
|
||||
# define PCSX2_PAGEFAULT_EXCEPT __except(SysPageFaultExceptionFilter(GetExceptionInformation())) {}
|
||||
|
@ -74,3 +94,8 @@ extern void InstallSignalHandler();
|
|||
#else
|
||||
# error PCSX2 - Unsupported operating system platform.
|
||||
#endif
|
||||
|
||||
|
||||
extern void InstallSignalHandler();
|
||||
|
||||
extern SrcType_PageFault Source_PageFault;
|
||||
|
|
|
@ -58,6 +58,27 @@ void SysThreadBase::OnStart()
|
|||
_parent::OnStart();
|
||||
}
|
||||
|
||||
// (overridable) Timeout period before a thread is considered potentially
|
||||
// deadlocked. SysThreadBase default is 4 seconds.
|
||||
//
|
||||
wxTimeSpan SysThreadBase::GetDeadlockTimeout() const
|
||||
{
|
||||
return wxTimeSpan( 0, 0, 4, 0 );
|
||||
}
|
||||
|
||||
void SysThreadBase::DoThreadDeadlocked()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SysThreadBase::ThrowDeadlockException()
|
||||
{
|
||||
throw Exception::ThreadDeadlock( *this,
|
||||
wxsFormat(L"Unhandled deadlock while suspending thread '%s'", m_name.c_str()),
|
||||
wxsFormat(L"'%s' thread is not responding to suspend requests. It may be deadlocked or just running *really* slow.", m_name.c_str())
|
||||
);
|
||||
}
|
||||
|
||||
// Suspends emulation and closes the emulation state (including plugins) at the next PS2 vsync,
|
||||
// and returns control to the calling thread; or does nothing if the core is already suspended.
|
||||
//
|
||||
|
@ -77,6 +98,9 @@ void SysThreadBase::OnStart()
|
|||
// Suspension must cansel itself forcefully or risk crashing whatever other action is
|
||||
// in progress.
|
||||
//
|
||||
// ThreadDeadlock - thrown if isBlocking is true and the thread to suspend fails to
|
||||
// respond within the timeout period returned by GetDeadlockTimeout().
|
||||
//
|
||||
bool SysThreadBase::Suspend( bool isBlocking )
|
||||
{
|
||||
if( IsSelf() || !IsRunning() ) return false;
|
||||
|
@ -112,15 +136,9 @@ bool SysThreadBase::Suspend( bool isBlocking )
|
|||
|
||||
if( isBlocking )
|
||||
{
|
||||
if( !m_RunningLock.Wait( wxTimeSpan( 0,0,3,0 ) ) )
|
||||
if( !m_RunningLock.Wait( GetDeadlockTimeout() ) )
|
||||
{
|
||||
// [TODO] : Implement proper deadlock handler here that lets the user continue
|
||||
// to wait, or issue a cancel to the thread.
|
||||
|
||||
throw Exception::ThreadTimedOut( *this,
|
||||
wxsFormat(L"Possible deadlock while suspending thread '%s'", m_name.c_str()),
|
||||
wxsFormat(L"'%s' thread is not responding to suspend requests. It may be deadlocked or just running *really* slow.", m_name.c_str())
|
||||
);
|
||||
DoThreadDeadlocked();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/Threading.h"
|
||||
#include "Utilities/PersistentThread.h"
|
||||
#include "x86emitter/tools.h"
|
||||
|
||||
using namespace Threading;
|
||||
|
@ -123,7 +123,11 @@ public:
|
|||
virtual bool AcquireResumeLock() { return m_ResumeProtection.TryAcquire(); }
|
||||
virtual void ReleaseResumeLock() { m_ResumeProtection.Release(); }
|
||||
|
||||
virtual wxTimeSpan GetDeadlockTimeout() const;
|
||||
virtual void ThrowDeadlockException();
|
||||
|
||||
protected:
|
||||
virtual void DoThreadDeadlocked();
|
||||
virtual void OnStart();
|
||||
|
||||
// This function is called by Resume immediately prior to releasing the suspension of
|
||||
|
|
192
pcsx2/gui/App.h
192
pcsx2/gui/App.h
|
@ -15,7 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "wxAppWithHelpers.h"
|
||||
#include "Utilities/wxAppWithHelpers.h"
|
||||
|
||||
#include <wx/fileconf.h>
|
||||
#include <wx/imaglist.h>
|
||||
|
@ -32,7 +32,7 @@
|
|||
class Pcsx2App;
|
||||
|
||||
typedef void FnType_OnThreadComplete(const wxCommandEvent& evt);
|
||||
typedef void (Pcsx2App::*FnType_AppMethod)();
|
||||
typedef void (Pcsx2App::*FnPtr_AppMethod)();
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
/*DECLARE_EVENT_TYPE( pxEVT_ReloadPlugins, -1 )
|
||||
|
@ -43,9 +43,11 @@ BEGIN_DECLARE_EVENT_TYPES()
|
|||
DECLARE_EVENT_TYPE( pxEvt_LoadPluginsComplete, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_PluginStatus, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_SysExecute, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_OpenModalDialog, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_InvokeMethod, -1 )
|
||||
DECLARE_EVENT_TYPE( pxEvt_LogicalVsync, -1 )
|
||||
|
||||
DECLARE_EVENT_TYPE( pxEvt_OpenModalDialog, -1 )
|
||||
//DECLARE_EVENT_TYPE( pxEvt_StuckThread, -1 )
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
// This is used when the GS plugin is handling its own window. Messages from the PAD
|
||||
|
@ -156,6 +158,25 @@ enum MenuIdentifiers
|
|||
MenuId_Config_ResetAll,
|
||||
};
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
// --------------------------------------------------------------------------
|
||||
// Exception used to perform an "errorless" termination of the app during OnInit
|
||||
// procedures. This happens when a user cancels out of startup prompts/wizards.
|
||||
//
|
||||
class StartupAborted : public BaseException
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( StartupAborted )
|
||||
|
||||
StartupAborted( const wxString& msg_eng=L"Startup initialization was aborted by the user." )
|
||||
{
|
||||
// english messages only for this exception.
|
||||
BaseException::InitBaseEx( msg_eng, msg_eng );
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// KeyAcceleratorCode
|
||||
|
@ -320,10 +341,12 @@ protected:
|
|||
u64 m_fpsqueue_tally;
|
||||
u64 m_ticks_lastframe;
|
||||
int m_fpsqueue_writepos;
|
||||
uint m_initpause;
|
||||
|
||||
uint m_FrameCounter;
|
||||
|
||||
public:
|
||||
FramerateManager() { Reset(); }
|
||||
virtual ~FramerateManager() throw() {}
|
||||
|
||||
void Reset();
|
||||
|
@ -345,18 +368,89 @@ class Pcsx2App : public wxAppWithHelpers
|
|||
// on them and they are, themselves, fairly self-contained.
|
||||
|
||||
protected:
|
||||
EventSource<PluginEventType>m_evtsrc_CorePluginStatus;
|
||||
CmdEvt_Source m_evtsrc_CoreThreadStatus;
|
||||
EventSource<int> m_evtsrc_SettingsApplied;
|
||||
EventSource<IniInterface> m_evtsrc_SettingsLoadSave;
|
||||
EventSource<AppEventType> m_evtsrc_AppStatus;
|
||||
|
||||
EventSource<IEventListener_Plugins> m_evtsrc_CorePluginStatus;
|
||||
EventSource<IEventListener_CoreThread> m_evtsrc_CoreThreadStatus;
|
||||
EventSource<IEventListener_AppStatus> m_evtsrc_AppStatus;
|
||||
|
||||
public:
|
||||
CmdEvt_Source& Source_CoreThreadStatus() { return m_evtsrc_CoreThreadStatus; }
|
||||
EventSource<int>& Source_SettingsApplied() { return m_evtsrc_SettingsApplied; }
|
||||
EventSource<AppEventType>& Source_AppStatus() { return m_evtsrc_AppStatus; }
|
||||
EventSource<PluginEventType>& Source_CorePluginStatus() { return m_evtsrc_CorePluginStatus; }
|
||||
EventSource<IniInterface>& Source_SettingsLoadSave() { return m_evtsrc_SettingsLoadSave; }
|
||||
void AddListener( IEventListener_Plugins& listener )
|
||||
{
|
||||
m_evtsrc_CorePluginStatus.Add( listener );
|
||||
}
|
||||
|
||||
void AddListener( IEventListener_CoreThread& listener )
|
||||
{
|
||||
m_evtsrc_CoreThreadStatus.Add( listener );
|
||||
}
|
||||
|
||||
void AddListener( IEventListener_AppStatus& listener )
|
||||
{
|
||||
m_evtsrc_AppStatus.Add( listener );
|
||||
}
|
||||
|
||||
void RemoveListener( IEventListener_Plugins& listener )
|
||||
{
|
||||
m_evtsrc_CorePluginStatus.Remove( listener );
|
||||
}
|
||||
|
||||
void RemoveListener( IEventListener_CoreThread& listener )
|
||||
{
|
||||
m_evtsrc_CoreThreadStatus.Remove( listener );
|
||||
}
|
||||
|
||||
void RemoveListener( IEventListener_AppStatus& listener )
|
||||
{
|
||||
m_evtsrc_AppStatus.Remove( listener );
|
||||
}
|
||||
|
||||
void AddListener( IEventListener_Plugins* listener )
|
||||
{
|
||||
m_evtsrc_CorePluginStatus.Add( listener );
|
||||
}
|
||||
|
||||
void AddListener( IEventListener_CoreThread* listener )
|
||||
{
|
||||
m_evtsrc_CoreThreadStatus.Add( listener );
|
||||
}
|
||||
|
||||
void AddListener( IEventListener_AppStatus* listener )
|
||||
{
|
||||
m_evtsrc_AppStatus.Add( listener );
|
||||
}
|
||||
|
||||
void RemoveListener( IEventListener_Plugins* listener )
|
||||
{
|
||||
m_evtsrc_CorePluginStatus.Remove( listener );
|
||||
}
|
||||
|
||||
void RemoveListener( IEventListener_CoreThread* listener )
|
||||
{
|
||||
m_evtsrc_CoreThreadStatus.Remove( listener );
|
||||
}
|
||||
|
||||
void RemoveListener( IEventListener_AppStatus* listener )
|
||||
{
|
||||
m_evtsrc_AppStatus.Remove( listener );
|
||||
}
|
||||
|
||||
void DispatchEvent( PluginEventType evt )
|
||||
{
|
||||
if( !AffinityAssert_AllowFromMain() ) return;
|
||||
m_evtsrc_CorePluginStatus.Dispatch( evt );
|
||||
}
|
||||
|
||||
void DispatchEvent( AppEventType evt )
|
||||
{
|
||||
if( !AffinityAssert_AllowFromMain() ) return;
|
||||
m_evtsrc_AppStatus.Dispatch( AppEventInfo( evt ) );
|
||||
}
|
||||
|
||||
void DispatchEvent( IniInterface& ini )
|
||||
{
|
||||
if( !AffinityAssert_AllowFromMain() ) return;
|
||||
m_evtsrc_AppStatus.Dispatch( AppSettingsEventInfo( ini ) );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
@ -374,13 +468,11 @@ public:
|
|||
ScopedPtr<PluginManager> m_CorePlugins;
|
||||
|
||||
protected:
|
||||
// Note: Pointers to frames should not be scoped because wxWidgets handles deletion
|
||||
// of these objects internally.
|
||||
MainEmuFrame* m_MainFrame;
|
||||
GSFrame* m_gsFrame;
|
||||
ConsoleLogFrame* m_ProgramLogBox;
|
||||
wxWindowID m_id_MainFrame;
|
||||
wxWindowID m_id_GsFrame;
|
||||
wxWindowID m_id_ProgramLogBox;
|
||||
|
||||
wxKeyEvent m_kevt;
|
||||
wxKeyEvent m_kevt;
|
||||
|
||||
public:
|
||||
Pcsx2App();
|
||||
|
@ -388,9 +480,9 @@ public:
|
|||
|
||||
void PostPluginStatus( PluginEventType pevt );
|
||||
void PostMenuAction( MenuIdentifiers menu_id ) const;
|
||||
int IssueModalDialog( const wxString& dlgName );
|
||||
|
||||
bool PrepForExit( bool canCancel );
|
||||
int IssueDialogAsModal( const wxString& dlgName );
|
||||
void PostMethod( FnPtr_AppMethod method );
|
||||
bool DoStuckThread( PersistentThread& stuck_thread );
|
||||
|
||||
void SysExecute();
|
||||
void SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override=wxEmptyString );
|
||||
|
@ -398,18 +490,33 @@ public:
|
|||
void ReloadPlugins();
|
||||
void LogicalVsync();
|
||||
|
||||
GSFrame& GetGSFrame() const;
|
||||
GSFrame* GetGSFramePtr() const { return m_gsFrame; }
|
||||
|
||||
GSFrame& GetGsFrame() const;
|
||||
MainEmuFrame& GetMainFrame() const;
|
||||
MainEmuFrame* GetMainFramePtr() const { return m_MainFrame; }
|
||||
bool HasMainFrame() const { return m_MainFrame != NULL; }
|
||||
|
||||
GSFrame* GetGsFramePtr() const { return (GSFrame*)wxWindow::FindWindowById( m_id_GsFrame ); }
|
||||
MainEmuFrame* GetMainFramePtr() const { return (MainEmuFrame*)wxWindow::FindWindowById( m_id_MainFrame ); }
|
||||
|
||||
bool HasMainFrame() const { return GetMainFramePtr() != NULL; }
|
||||
|
||||
void OpenGsPanel();
|
||||
void CloseGsPanel();
|
||||
void OnGsFrameClosed();
|
||||
void OnMainFrameClosed();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Startup / Shutdown Helpers
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
void DetectCpuAndUserMode();
|
||||
void OpenConsoleLog();
|
||||
void OpenMainFrame();
|
||||
bool PrepForExit( bool canCancel );
|
||||
void CleanupRestartable();
|
||||
void CleanupResources();
|
||||
void WipeUserModeSettings();
|
||||
void ReadUserModeSettings();
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// App-wide Resources
|
||||
// --------------------------------------------------------------------------
|
||||
|
@ -446,6 +553,7 @@ public:
|
|||
// Console / Program Logging Helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
ConsoleLogFrame* GetProgramLog();
|
||||
const ConsoleLogFrame* GetProgramLog() const;
|
||||
void ProgramLog_PostEvent( wxEvent& evt );
|
||||
void EnableAllLogging() const;
|
||||
void DisableWindowLogging() const;
|
||||
|
@ -453,16 +561,17 @@ public:
|
|||
void OnProgramLogClosed();
|
||||
|
||||
protected:
|
||||
bool SelfMethodInvoke( FnType_AppMethod method );
|
||||
bool SelfMethodPost( FnType_AppMethod method );
|
||||
bool InvokeMethodOnMainThread( FnPtr_AppMethod method );
|
||||
bool PostMethodToMainThread( FnPtr_AppMethod method );
|
||||
|
||||
void AllocateCoreStuffs();
|
||||
void InitDefaultGlobalAccelerators();
|
||||
void BuildCommandHash();
|
||||
void ReadUserModeSettings();
|
||||
bool TryOpenConfigCwd();
|
||||
void CleanupMess();
|
||||
void CleanupOnExit();
|
||||
void OpenWizardConsole();
|
||||
void PadKeyDispatch( const keyEvent& ev );
|
||||
void CancelLoadingPlugins();
|
||||
|
||||
void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event) const;
|
||||
void HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& event);
|
||||
|
@ -470,10 +579,12 @@ protected:
|
|||
void OnSysExecute( wxCommandEvent& evt );
|
||||
void OnLoadPluginsComplete( wxCommandEvent& evt );
|
||||
void OnPluginStatus( wxCommandEvent& evt );
|
||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||
void OnCoreThreadStatus( wxCommandEvent& evt );
|
||||
void OnFreezeThreadFinished( wxCommandEvent& evt );
|
||||
|
||||
void OnOpenModalDialog( wxCommandEvent& evt );
|
||||
void OnOpenDialog_StuckThread( wxCommandEvent& evt );
|
||||
|
||||
void OnEmuKeyDown( wxKeyEvent& evt );
|
||||
|
||||
void OnInvokeMethod( pxInvokeMethodEvent& evt );
|
||||
|
@ -497,17 +608,6 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// AppCoreThread class
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
enum CoreThreadStatus
|
||||
{
|
||||
CoreStatus_Indeterminate,
|
||||
CoreStatus_Started,
|
||||
CoreStatus_Resumed,
|
||||
CoreStatus_Suspended,
|
||||
CoreStatus_Reset,
|
||||
CoreStatus_Stopped,
|
||||
};
|
||||
|
||||
class AppCoreThread : public SysCoreThread
|
||||
{
|
||||
typedef SysCoreThread _parent;
|
||||
|
@ -533,6 +633,8 @@ protected:
|
|||
virtual void PostVsyncToUI();
|
||||
virtual void ExecuteTaskInThread();
|
||||
virtual void DoCpuReset();
|
||||
|
||||
virtual void DoThreadDeadlocked();
|
||||
};
|
||||
|
||||
DECLARE_APP(Pcsx2App)
|
||||
|
@ -568,7 +670,7 @@ DECLARE_APP(Pcsx2App)
|
|||
if( MainEmuFrame* __frame_ = GetMainFramePtr() ) (*__frame_)
|
||||
|
||||
#define sGSFrame \
|
||||
if( GSFrame* __gsframe_ = wxGetApp().GetGSFramePtr() ) (*__gsframe_)
|
||||
if( GSFrame* __gsframe_ = wxGetApp().GetGsFramePtr() ) (*__gsframe_)
|
||||
|
||||
// Use this within the scope of a wxWindow (wxDialog or wxFrame). If the window has a valid menu
|
||||
// bar, the command will run, otherwise it will be silently ignored. :)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "Utilities/SafeArray.h"
|
||||
#include "Utilities/EventSource.h"
|
||||
#include "Utilities/Threading.h"
|
||||
#include "Utilities/PersistentThread.h"
|
||||
|
||||
#include "Utilities/wxGuiTools.h"
|
||||
#include "Utilities/pxRadioPanel.h"
|
||||
|
@ -25,37 +25,6 @@
|
|||
#include "Utilities/pxStaticText.h"
|
||||
#include "Utilities/CheckedStaticBox.h"
|
||||
|
||||
class MainEmuFrame;
|
||||
class GSFrame;
|
||||
class ConsoleLogFrame;
|
||||
class PipeRedirectionBase;
|
||||
class AppCoreThread;
|
||||
class pxInvokeMethodEvent;
|
||||
|
||||
// wxWidgets forward declarations
|
||||
|
||||
class wxDirPickerCtrl;
|
||||
class wxFileDirPickerEvent;
|
||||
class wxListBox;
|
||||
class wxListbook;
|
||||
class wxBookCtrlBase;
|
||||
|
||||
enum AppEventType
|
||||
{
|
||||
// Maybe this will be expanded upon later..?
|
||||
AppStatus_Exiting
|
||||
};
|
||||
|
||||
enum PluginEventType
|
||||
{
|
||||
PluginsEvt_Loaded,
|
||||
PluginsEvt_Init,
|
||||
PluginsEvt_Opening, // dispatched prior to plugins being opened
|
||||
PluginsEvt_Opened, // dispatched after plugins are opened
|
||||
PluginsEvt_Closing, // dispatched prior to plugins being closed
|
||||
PluginsEvt_Closed, // dispatched after plugins are closed
|
||||
PluginsEvt_Shutdown,
|
||||
PluginsEvt_Unloaded,
|
||||
};
|
||||
|
||||
#include "AppForwardDefs.h"
|
||||
#include "AppConfig.h"
|
||||
#include "AppEventListeners.h"
|
|
@ -683,16 +683,11 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite )
|
|||
throw Exception::AccessDenied( "Failed to overwrite settings; permission to file was denied." );
|
||||
}
|
||||
|
||||
//if( GetAppConfig() != NULL )
|
||||
// wxGetApp().Source_SettingsChanged().Dispatch( SettingsEvt_IniClosing );
|
||||
|
||||
// Bind into wxConfigBase to allow wx to use our config internally, and delete whatever
|
||||
// comes out (cleans up prev config, if one).
|
||||
delete wxConfigBase::Set( OpenFileConfig( iniFilename ) );
|
||||
GetAppConfig()->SetRecordDefaults();
|
||||
|
||||
//wxGetApp().Source_SettingsChanged().Dispatch( SettingsEvt_IniOpening );
|
||||
|
||||
if( !overwrite )
|
||||
AppLoadSettings();
|
||||
|
||||
|
|
|
@ -15,13 +15,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "AppForwardDefs.h"
|
||||
#include "PathDefs.h"
|
||||
#include "CDVD/CDVDaccess.h"
|
||||
|
||||
class IniInterface;
|
||||
class wxConfigBase;
|
||||
class wxFileConfig;
|
||||
|
||||
extern bool UseAdminMode; // dictates if the program uses /home/user or /cwd for the program data
|
||||
extern wxDirName SettingsFolder; // dictates where the settings folder comes from, *if* UseDefaultSettingsFolder is FALSE.
|
||||
extern bool UseDefaultSettingsFolder; // when TRUE, pcsx2 derives the settings folder from the UseAdminMode
|
||||
|
|
|
@ -33,10 +33,10 @@ AppCoreThread::~AppCoreThread() throw()
|
|||
|
||||
void AppCoreThread::Cancel( bool isBlocking )
|
||||
{
|
||||
if( !_parent::Cancel( wxTimeSpan( 0,0,1,0 ) ) )
|
||||
if( !_parent::Cancel( wxTimeSpan( 0, 0, 2, 0 ) ) )
|
||||
{
|
||||
// Possible deadlock!
|
||||
throw Exception::ThreadTimedOut( this );
|
||||
throw Exception::ThreadDeadlock( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,11 +46,18 @@ void AppCoreThread::Reset()
|
|||
_parent::Reset();
|
||||
}
|
||||
|
||||
void AppCoreThread::DoThreadDeadlocked()
|
||||
{
|
||||
//wxGetApp().PostCommand( );
|
||||
wxGetApp().DoStuckThread( *this );
|
||||
}
|
||||
|
||||
bool AppCoreThread::Suspend( bool isBlocking )
|
||||
{
|
||||
ScopedBusyCursor::SetDefault( Cursor_KindaBusy );
|
||||
bool retval = _parent::Suspend( isBlocking );
|
||||
|
||||
bool retval = _parent::Suspend( false );
|
||||
|
||||
if( !retval || isBlocking )
|
||||
ScopedBusyCursor::SetDefault( Cursor_NotBusy );
|
||||
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/EventSource.h"
|
||||
|
||||
enum CoreThreadStatus
|
||||
{
|
||||
CoreStatus_Indeterminate,
|
||||
CoreStatus_Started,
|
||||
CoreStatus_Resumed,
|
||||
CoreStatus_Suspended,
|
||||
CoreStatus_Reset,
|
||||
CoreStatus_Stopped,
|
||||
};
|
||||
|
||||
enum AppEventType
|
||||
{
|
||||
AppStatus_SettingsLoaded,
|
||||
AppStatus_SettingsSaved,
|
||||
AppStatus_SettingsApplied,
|
||||
AppStatus_Exiting
|
||||
};
|
||||
|
||||
enum PluginEventType
|
||||
{
|
||||
PluginsEvt_Loaded,
|
||||
PluginsEvt_Init,
|
||||
PluginsEvt_Opening, // dispatched prior to plugins being opened
|
||||
PluginsEvt_Opened, // dispatched after plugins are opened
|
||||
PluginsEvt_Closing, // dispatched prior to plugins being closed
|
||||
PluginsEvt_Closed, // dispatched after plugins are closed
|
||||
PluginsEvt_Shutdown,
|
||||
PluginsEvt_Unloaded,
|
||||
};
|
||||
|
||||
struct AppEventInfo
|
||||
{
|
||||
AppEventType evt_type;
|
||||
|
||||
AppEventInfo( AppEventType type )
|
||||
{
|
||||
evt_type = type;
|
||||
}
|
||||
};
|
||||
|
||||
struct AppSettingsEventInfo : AppEventInfo
|
||||
{
|
||||
IniInterface& m_ini;
|
||||
|
||||
AppSettingsEventInfo( IniInterface& ini );
|
||||
|
||||
IniInterface& GetIni() const
|
||||
{
|
||||
return const_cast<IniInterface&>(m_ini);
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventListener_CoreThread
|
||||
// --------------------------------------------------------------------------------------
|
||||
class IEventListener_CoreThread : public IEventDispatcher<CoreThreadStatus>
|
||||
{
|
||||
public:
|
||||
typedef CoreThreadStatus EvtParams;
|
||||
|
||||
public:
|
||||
IEventListener_CoreThread();
|
||||
virtual ~IEventListener_CoreThread() throw();
|
||||
|
||||
virtual void DispatchEvent( const CoreThreadStatus& status )
|
||||
{
|
||||
switch( status )
|
||||
{
|
||||
case CoreStatus_Indeterminate: OnCoreStatus_Indeterminate(); break;
|
||||
case CoreStatus_Started: OnCoreStatus_Started(); break;
|
||||
case CoreStatus_Resumed: OnCoreStatus_Resumed(); break;
|
||||
case CoreStatus_Suspended: OnCoreStatus_Suspended(); break;
|
||||
case CoreStatus_Reset: OnCoreStatus_Reset(); break;
|
||||
case CoreStatus_Stopped: OnCoreStatus_Stopped(); break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void OnCoreStatus_Indeterminate() {}
|
||||
virtual void OnCoreStatus_Started() {}
|
||||
virtual void OnCoreStatus_Resumed() {}
|
||||
virtual void OnCoreStatus_Suspended() {}
|
||||
virtual void OnCoreStatus_Reset() {}
|
||||
virtual void OnCoreStatus_Stopped() {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventListener_Plugins
|
||||
// --------------------------------------------------------------------------------------
|
||||
class IEventListener_Plugins : public IEventDispatcher<PluginEventType>
|
||||
{
|
||||
public:
|
||||
typedef PluginEventType EvtParams;
|
||||
|
||||
public:
|
||||
IEventListener_Plugins();
|
||||
virtual ~IEventListener_Plugins() throw();
|
||||
|
||||
virtual void DispatchEvent( const PluginEventType& pevt )
|
||||
{
|
||||
switch( pevt )
|
||||
{
|
||||
case PluginsEvt_Loaded: OnPluginsEvt_Loaded(); break;
|
||||
case PluginsEvt_Init: OnPluginsEvt_Init(); break;
|
||||
case PluginsEvt_Opening: OnPluginsEvt_Opening(); break;
|
||||
case PluginsEvt_Opened: OnPluginsEvt_Opened(); break;
|
||||
case PluginsEvt_Closing: OnPluginsEvt_Closing(); break;
|
||||
case PluginsEvt_Closed: OnPluginsEvt_Closed(); break;
|
||||
case PluginsEvt_Shutdown: OnPluginsEvt_Shutdown(); break;
|
||||
case PluginsEvt_Unloaded: OnPluginsEvt_Unloaded(); break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void OnPluginsEvt_Loaded() {}
|
||||
virtual void OnPluginsEvt_Init() {}
|
||||
virtual void OnPluginsEvt_Opening() {} // dispatched prior to plugins being opened
|
||||
virtual void OnPluginsEvt_Opened() {} // dispatched after plugins are opened
|
||||
virtual void OnPluginsEvt_Closing() {} // dispatched prior to plugins being closed
|
||||
virtual void OnPluginsEvt_Closed() {} // dispatched after plugins are closed
|
||||
virtual void OnPluginsEvt_Shutdown() {}
|
||||
virtual void OnPluginsEvt_Unloaded() {}
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventListener_AppStatus
|
||||
// --------------------------------------------------------------------------------------
|
||||
class IEventListener_AppStatus : public IEventDispatcher<AppEventInfo>
|
||||
{
|
||||
public:
|
||||
typedef AppEventInfo EvtParams;
|
||||
|
||||
public:
|
||||
IEventListener_AppStatus();
|
||||
virtual ~IEventListener_AppStatus() throw();
|
||||
|
||||
virtual void DispatchEvent( const AppEventInfo& evtinfo );
|
||||
|
||||
protected:
|
||||
virtual void AppStatusEvent_OnSettingsLoadSave( const AppSettingsEventInfo& evtinfo ) {}
|
||||
virtual void AppStatusEvent_OnSettingsApplied() {}
|
||||
virtual void AppStatusEvent_OnExit() {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventListenerHelper_AppStatus
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Welcome to the awkward world of C++ multi-inheritence. wxWidgets' Connect() system is
|
||||
// incompatible because of limitations in C++ class member function pointers, so we need
|
||||
// this second layer class to act as a bridge between the event system and the class's
|
||||
// handler implementations.
|
||||
//
|
||||
template< typename TypeToDispatchTo >
|
||||
class EventListenerHelper_AppStatus : public IEventListener_AppStatus
|
||||
{
|
||||
public:
|
||||
TypeToDispatchTo& Owner;
|
||||
|
||||
public:
|
||||
EventListenerHelper_AppStatus( TypeToDispatchTo& dispatchTo )
|
||||
: Owner( dispatchTo )
|
||||
{
|
||||
}
|
||||
|
||||
EventListenerHelper_AppStatus( TypeToDispatchTo* dispatchTo )
|
||||
: Owner( *dispatchTo )
|
||||
{
|
||||
pxAssume(dispatchTo != NULL);
|
||||
}
|
||||
|
||||
virtual ~EventListenerHelper_AppStatus() throw() {}
|
||||
|
||||
protected:
|
||||
virtual void AppStatusEvent_OnSettingsLoadSave( const AppSettingsEventInfo& evtinfo ) { Owner.AppStatusEvent_OnSettingsLoadSave( evtinfo ); }
|
||||
virtual void AppStatusEvent_OnSettingsApplied() { Owner.AppStatusEvent_OnSettingsApplied(); }
|
||||
virtual void AppStatusEvent_OnExit() { Owner.AppStatusEvent_OnExit(); }
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
/* 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 "IniInterface.h"
|
||||
#include "Utilities/EventSource.inl"
|
||||
|
||||
template class EventSource< IEventListener_CoreThread >;
|
||||
template class EventSource< IEventListener_Plugins >;
|
||||
template class EventSource< IEventListener_AppStatus >;
|
||||
|
||||
AppSettingsEventInfo::AppSettingsEventInfo( IniInterface& ini )
|
||||
: AppEventInfo( ini.IsSaving() ? AppStatus_SettingsSaved : AppStatus_SettingsLoaded )
|
||||
, m_ini( ini )
|
||||
{
|
||||
}
|
||||
|
||||
IEventListener_CoreThread::IEventListener_CoreThread()
|
||||
{
|
||||
wxGetApp().AddListener( this );
|
||||
}
|
||||
|
||||
IEventListener_CoreThread::~IEventListener_CoreThread() throw()
|
||||
{
|
||||
wxGetApp().RemoveListener( this );
|
||||
}
|
||||
|
||||
IEventListener_Plugins::IEventListener_Plugins()
|
||||
{
|
||||
wxGetApp().AddListener( this );
|
||||
}
|
||||
|
||||
IEventListener_Plugins::~IEventListener_Plugins() throw()
|
||||
{
|
||||
wxGetApp().RemoveListener( this );
|
||||
}
|
||||
|
||||
IEventListener_AppStatus::IEventListener_AppStatus()
|
||||
{
|
||||
wxGetApp().AddListener( this );
|
||||
}
|
||||
|
||||
IEventListener_AppStatus::~IEventListener_AppStatus() throw()
|
||||
{
|
||||
wxGetApp().RemoveListener( this );
|
||||
}
|
||||
|
||||
void IEventListener_AppStatus::DispatchEvent( const AppEventInfo& evtinfo )
|
||||
{
|
||||
switch( evtinfo.evt_type )
|
||||
{
|
||||
case AppStatus_SettingsLoaded:
|
||||
case AppStatus_SettingsSaved:
|
||||
AppStatusEvent_OnSettingsLoadSave( (const AppSettingsEventInfo&)evtinfo );
|
||||
break;
|
||||
|
||||
case AppStatus_SettingsApplied: AppStatusEvent_OnSettingsApplied(); break;
|
||||
case AppStatus_Exiting: AppStatusEvent_OnExit(); break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// AppForwardDefs.h
|
||||
//
|
||||
// Purpose:
|
||||
// This header file is meant to be a dependency-free include that provides a relatively
|
||||
// full compliment of forward defines for PCSX2/App and wxwidgets types. When
|
||||
// forward defined in this way, these types can be used by method and class definitions
|
||||
// as either pointers or handles without running into complicated header file
|
||||
// inter-dependence.
|
||||
//
|
||||
|
||||
class MainEmuFrame;
|
||||
class GSFrame;
|
||||
class ConsoleLogFrame;
|
||||
class PipeRedirectionBase;
|
||||
class AppCoreThread;
|
||||
class pxInvokeMethodEvent;
|
||||
class IniInterface;
|
||||
|
||||
// wxWidgets forward declarations
|
||||
|
||||
class wxConfigBase;
|
||||
class wxFileConfig;
|
||||
class wxDirPickerCtrl;
|
||||
class wxFileDirPickerEvent;
|
||||
class wxListBox;
|
||||
class wxListbook;
|
||||
class wxBookCtrlBase;
|
|
@ -28,25 +28,6 @@
|
|||
|
||||
static bool m_ForceWizard = false;
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
// --------------------------------------------------------------------------
|
||||
// Exception used to perform an "errorless" termination of the app during OnInit
|
||||
// procedures. This happens when a user cancels out of startup prompts/wizards.
|
||||
//
|
||||
class StartupAborted : public BaseException
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( StartupAborted )
|
||||
|
||||
StartupAborted( const wxString& msg_eng=L"Startup initialization was aborted by the user." )
|
||||
{
|
||||
// english messages only for this exception.
|
||||
BaseException::InitBaseEx( msg_eng, msg_eng );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void CpuCheckSSE2()
|
||||
{
|
||||
if( x86caps.hasStreamingSIMD2Extensions ) return;
|
||||
|
@ -77,10 +58,28 @@ void Pcsx2App::OpenWizardConsole()
|
|||
{
|
||||
if( !IsDebugBuild ) return;
|
||||
g_Conf->ProgLogBox.Visible = true;
|
||||
m_ProgramLogBox = new ConsoleLogFrame( NULL, L"PCSX2 Program Log", g_Conf->ProgLogBox );
|
||||
m_id_ProgramLogBox = (new ConsoleLogFrame( NULL, L"PCSX2 Program Log", g_Conf->ProgLogBox ))->GetId();
|
||||
EnableAllLogging();
|
||||
}
|
||||
|
||||
void Pcsx2App::WipeUserModeSettings()
|
||||
{
|
||||
wxDirName usrlocaldir( wxStandardPaths::Get().GetUserLocalDataDir() );
|
||||
if( !usrlocaldir.Exists() ) return;
|
||||
|
||||
wxString cwd( Path::Normalize( wxGetCwd() ) );
|
||||
u32 hashres = HashTools::Hash( (char*)cwd.c_str(), cwd.Length() );
|
||||
|
||||
wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() );
|
||||
usermodefile.SetPath( usrlocaldir.ToString() );
|
||||
ScopedPtr<wxFileConfig> conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) );
|
||||
|
||||
wxString groupname( wxsFormat( L"CWD.%08x", hashres ) );
|
||||
Console.WriteLn( "(UserModeSettings) Removing entry:" );
|
||||
Console.Indent().WriteLn( L"Path: %s\nHash:%s", cwd.c_str(), groupname.c_str() );
|
||||
conf_usermode->DeleteGroup( groupname );
|
||||
}
|
||||
|
||||
// User mode settings can't be stored in the CWD for two reasons:
|
||||
// (a) the user may not have permission to do so (most obvious)
|
||||
// (b) it would result in sloppy usermode.ini found all over a hard drive if people runs the
|
||||
|
@ -91,9 +90,6 @@ void Pcsx2App::OpenWizardConsole()
|
|||
//
|
||||
void Pcsx2App::ReadUserModeSettings()
|
||||
{
|
||||
wxString cwd( Path::Normalize( wxGetCwd() ) );
|
||||
u32 hashres = HashTools::Hash( (char*)cwd.c_str(), cwd.Length() );
|
||||
|
||||
wxDirName usrlocaldir( wxStandardPaths::Get().GetUserLocalDataDir() );
|
||||
if( !usrlocaldir.Exists() )
|
||||
{
|
||||
|
@ -101,6 +97,9 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
usrlocaldir.Mkdir();
|
||||
}
|
||||
|
||||
wxString cwd( Path::Normalize( wxGetCwd() ) );
|
||||
u32 hashres = HashTools::Hash( (char*)cwd.c_str(), cwd.Length() );
|
||||
|
||||
wxFileName usermodefile( FilenameDefs::GetUsermodeConfig() );
|
||||
usermodefile.SetPath( usrlocaldir.ToString() );
|
||||
ScopedPtr<wxFileConfig> conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) );
|
||||
|
@ -181,8 +180,146 @@ void Pcsx2App::ReadUserModeSettings()
|
|||
// force a reset here to unload plugins loaded by the wizard. If we don't do this
|
||||
// the recompilers might fail to allocate the memory they need to function.
|
||||
SysReset();
|
||||
sys_resume_lock = 0;
|
||||
}
|
||||
|
||||
void Pcsx2App::DetectCpuAndUserMode()
|
||||
{
|
||||
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.
|
||||
throw Exception::HardwareDeficiency(L"MMX Extensions not available.", _("PCSX2 requires cpu with MMX instruction to run."));
|
||||
}
|
||||
|
||||
ReadUserModeSettings();
|
||||
AppConfig_OnChangedSettingsFolder();
|
||||
|
||||
PostMethod( &Pcsx2App::OpenMainFrame );
|
||||
PostMethod( &Pcsx2App::OpenConsoleLog );
|
||||
PostMethod( &Pcsx2App::AllocateCoreStuffs );
|
||||
}
|
||||
|
||||
void Pcsx2App::OpenMainFrame()
|
||||
{
|
||||
if( GetMainFramePtr() != NULL ) return;
|
||||
|
||||
MainEmuFrame* mainFrame = new MainEmuFrame( NULL, L"PCSX2" );
|
||||
m_id_MainFrame = mainFrame->GetId();
|
||||
mainFrame->PushEventHandler( &GetRecentIsoList() );
|
||||
|
||||
if( wxWindow* deleteme = GetProgramLog() )
|
||||
{
|
||||
deleteme->Destroy();
|
||||
g_Conf->ProgLogBox.Visible = true;
|
||||
PostMethod( &Pcsx2App::OpenConsoleLog );
|
||||
}
|
||||
|
||||
SetTopWindow( mainFrame ); // not really needed...
|
||||
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
|
||||
mainFrame->Show();
|
||||
}
|
||||
|
||||
void Pcsx2App::OpenConsoleLog()
|
||||
{
|
||||
if( GetProgramLog() != NULL ) return;
|
||||
m_id_ProgramLogBox = (new ConsoleLogFrame( GetMainFramePtr(), L"PCSX2 Program Log", g_Conf->ProgLogBox ))->GetId();
|
||||
EnableAllLogging();
|
||||
}
|
||||
|
||||
void Pcsx2App::AllocateCoreStuffs()
|
||||
{
|
||||
CpuCheckSSE2();
|
||||
SysLogMachineCaps();
|
||||
AppApplySettings();
|
||||
|
||||
if( m_CoreAllocs ) return;
|
||||
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 );
|
||||
|
||||
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" )
|
||||
);
|
||||
|
||||
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() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
|
||||
|
||||
g_Conf->EmuOptions.Recompiler.EnableEE = false;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_IOP() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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",
|
||||
L"These errors are the result of memory allocation failures (see the program log for details). "
|
||||
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
|
||||
L"These recompilers have been disabled and interpreters will be used in their place. "
|
||||
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;
|
||||
}
|
||||
|
||||
LoadPluginsPassive( NULL );
|
||||
}
|
||||
|
||||
|
||||
void Pcsx2App::OnInitCmdLine( wxCmdLineParser& parser )
|
||||
{
|
||||
parser.SetLogo( (wxString)L" >> PCSX2 -- A Playstation2 Emulator for the PC <<\n\n" +
|
||||
|
@ -261,14 +398,14 @@ bool Pcsx2App::OnCmdLineParsed( wxCmdLineParser& parser )
|
|||
}
|
||||
|
||||
typedef void (wxEvtHandler::*pxInvokeMethodEventFunction)(pxInvokeMethodEvent&);
|
||||
typedef void (wxEvtHandler::*pxStuckThreadEventHandler)(pxMessageBoxEvent&);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
bool Pcsx2App::OnInit()
|
||||
{
|
||||
#define pxMethodEventHandler(func) \
|
||||
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxInvokeMethodEventFunction, &func )
|
||||
|
||||
Connect( pxEvt_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||
Connect( pxEvt_OpenModalDialog, wxCommandEventHandler( Pcsx2App::OnOpenModalDialog ) );
|
||||
|
||||
pxDoAssert = AppDoAssert;
|
||||
|
||||
|
@ -282,11 +419,6 @@ bool Pcsx2App::OnInit()
|
|||
m_StderrRedirHandle = NewPipeRedir(stderr);
|
||||
wxLocale::AddCatalogLookupPathPrefix( wxGetCwd() );
|
||||
|
||||
/*Connect( pxEVT_ReloadPlugins, wxCommandEventHandler (Pcsx2App::OnReloadPlugins) );
|
||||
|
||||
Connect( pxEVT_LogicalVsync, wxCommandEventHandler (Pcsx2App::OnLogicalVsync) );
|
||||
Connect( pxEVT_OpenGsPanel, wxCommandEventHandler (Pcsx2App::OpenGsPanel) );*/
|
||||
|
||||
Connect( pxEvt_FreezeThreadFinished, wxCommandEventHandler (Pcsx2App::OnFreezeThreadFinished) );
|
||||
Connect( pxEvt_CoreThreadStatus, wxCommandEventHandler (Pcsx2App::OnCoreThreadStatus) );
|
||||
Connect( pxEvt_LoadPluginsComplete, wxCommandEventHandler (Pcsx2App::OnLoadPluginsComplete) );
|
||||
|
@ -314,135 +446,23 @@ 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() );
|
||||
|
||||
if( m_ProgramLogBox )
|
||||
{
|
||||
wxWindow* deleteme = m_ProgramLogBox;
|
||||
OnProgramLogClosed();
|
||||
delete deleteme;
|
||||
g_Conf->ProgLogBox.Visible = true;
|
||||
}
|
||||
|
||||
m_ProgramLogBox = new ConsoleLogFrame( m_MainFrame, L"PCSX2 Program Log", g_Conf->ProgLogBox );
|
||||
EnableAllLogging();
|
||||
|
||||
SetTopWindow( m_MainFrame ); // not really needed...
|
||||
SetExitOnFrameDelete( true ); // but being explicit doesn't hurt...
|
||||
m_MainFrame->Show();
|
||||
|
||||
SysLogMachineCaps();
|
||||
|
||||
AppApplySettings();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
pxDwm_Load();
|
||||
#endif
|
||||
|
||||
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 );
|
||||
|
||||
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" )
|
||||
);
|
||||
|
||||
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() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R5900 (EE)\n\n" );
|
||||
|
||||
g_Conf->EmuOptions.Recompiler.EnableEE = false;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_IOP() )
|
||||
{
|
||||
scrollableTextArea->AppendText( L"* R3000A (IOP)\n\n" );
|
||||
g_Conf->EmuOptions.Recompiler.EnableIOP = false;
|
||||
}
|
||||
|
||||
if( !m_CoreAllocs->IsRecAvailable_MicroVU0() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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() )
|
||||
{
|
||||
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",
|
||||
L"These errors are the result of memory allocation failures (see the program log for details). "
|
||||
L"Closing out some memory hogging background tasks may resolve this error.\n\n"
|
||||
L"These recompilers have been disabled and interpreters will be used in their place. "
|
||||
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;
|
||||
}
|
||||
|
||||
LoadPluginsPassive( NULL );
|
||||
DetectCpuAndUserMode();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::StartupAborted& ex )
|
||||
catch( Exception::StartupAborted& ex ) // user-aborted, no popups needed.
|
||||
{
|
||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
CleanupMess();
|
||||
CleanupOnExit();
|
||||
return false;
|
||||
}
|
||||
catch( Exception::HardwareDeficiency& ex )
|
||||
{
|
||||
Msgbox::Alert( ex.FormatDisplayMessage() + _("\n\nPress OK to close PCSX2."), _("PCSX2 Error: Hardware Deficiency") );
|
||||
CleanupOnExit();
|
||||
return false;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -453,29 +473,52 @@ bool Pcsx2App::OnInit()
|
|||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
Console.Error( ex.FormatDiagnosticMessage() );
|
||||
Msgbox::Alert( ex.FormatDisplayMessage() + L"\n\nPress OK to close PCSX2.",
|
||||
Msgbox::Alert( ex.FormatDisplayMessage() + _("\n\nPress OK to close PCSX2."),
|
||||
_("PCSX2 Critical Error"), wxICON_ERROR );
|
||||
CleanupOnExit();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Pcsx2App::CleanupMess()
|
||||
// This cleanup procedure can only be called when the App message pump is still active.
|
||||
// OnExit() must use CleanupOnExit instead.
|
||||
void Pcsx2App::CleanupRestartable()
|
||||
{
|
||||
// app is shutting down, so don't let the system resume for anything. (sometimes there
|
||||
// are pending Resume messages in the queue from previous user actions)
|
||||
AffinityAssert_AllowFromMain();
|
||||
|
||||
// app is shutting down, so don't let the system resume for anything. (sometimes
|
||||
// there are pending Resume messages in the queue from previous user actions, and
|
||||
// this will block them from executing).
|
||||
sys_resume_lock += 10;
|
||||
|
||||
PingDispatcher( "Cleanup" );
|
||||
DeletionDispatcher();
|
||||
|
||||
CoreThread.Cancel();
|
||||
|
||||
if( m_CorePlugins )
|
||||
m_CorePlugins->Shutdown();
|
||||
|
||||
if( g_Conf )
|
||||
AppSaveSettings();
|
||||
|
||||
sMainFrame.RemoveEventHandler( &GetRecentIsoList() );
|
||||
}
|
||||
|
||||
// This cleanup handler can be called from OnExit (it doesn't need a running message pump),
|
||||
// but should not be called from the App destructor. It's needed because wxWidgets doesn't
|
||||
// always call OnExit(), so I had to make CleanupRestartable, and then encapsulate it here
|
||||
// to be friendly to the OnExit scenario (no message pump).
|
||||
void Pcsx2App::CleanupOnExit()
|
||||
{
|
||||
AffinityAssert_AllowFromMain();
|
||||
|
||||
try
|
||||
{
|
||||
sys_resume_lock += 10;
|
||||
|
||||
PingDispatch( "Cleanup" );
|
||||
CoreThread.Cancel();
|
||||
|
||||
if( m_CorePlugins )
|
||||
m_CorePlugins->Shutdown();
|
||||
CleanupRestartable();
|
||||
}
|
||||
catch( Exception::ThreadTimedOut& ) { throw; }
|
||||
catch( Exception::ThreadDeadlock& ) { throw; }
|
||||
catch( Exception::CancelEvent& ) { throw; }
|
||||
catch( Exception::RuntimeError& ex )
|
||||
{
|
||||
|
@ -483,7 +526,7 @@ void Pcsx2App::CleanupMess()
|
|||
// that we just don't care about by now, and just want to "get 'er done!" so
|
||||
// we can exit the app. ;)
|
||||
|
||||
Console.Error( L"Runtime exception handled during CleanupMess:\n" );
|
||||
Console.Error( L"Runtime exception handled during CleanupOnExit:\n" );
|
||||
Console.Indent().Error( ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
|
||||
|
@ -499,17 +542,33 @@ void Pcsx2App::CleanupMess()
|
|||
|
||||
// FIXME: performing a wxYield() here may fix that problem. -- air
|
||||
|
||||
pxDoAssert = pxAssertImpl_LogIt;
|
||||
Console_SetActiveHandler( ConsoleWriter_Stdout );
|
||||
}
|
||||
|
||||
void Pcsx2App::CleanupResources()
|
||||
{
|
||||
delete wxConfigBase::Set( NULL );
|
||||
|
||||
while( wxGetLocale() != NULL )
|
||||
delete wxGetLocale();
|
||||
|
||||
pxDoAssert = pxAssertImpl_LogIt;
|
||||
}
|
||||
|
||||
int Pcsx2App::OnExit()
|
||||
{
|
||||
CleanupOnExit();
|
||||
CleanupResources();
|
||||
m_Resources = NULL;
|
||||
|
||||
return wxApp::OnExit();
|
||||
}
|
||||
|
||||
|
||||
Pcsx2App::Pcsx2App()
|
||||
{
|
||||
m_MainFrame = NULL;
|
||||
m_gsFrame = NULL;
|
||||
m_ProgramLogBox = NULL;
|
||||
m_id_MainFrame = wxID_ANY;
|
||||
m_id_GsFrame = wxID_ANY;
|
||||
m_id_ProgramLogBox = wxID_ANY;
|
||||
|
||||
SetAppName( L"pcsx2" );
|
||||
BuildCommandHash();
|
||||
|
@ -519,16 +578,10 @@ 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.
|
||||
CleanupResources();
|
||||
m_Resources = NULL;
|
||||
DisableDiskLogging();
|
||||
|
||||
CleanupMess();
|
||||
|
||||
delete wxConfigBase::Set( NULL );
|
||||
|
||||
Console_SetActiveHandler( ConsoleWriter_Null );
|
||||
|
||||
if( emuLog != NULL )
|
||||
{
|
||||
fclose( emuLog );
|
||||
|
|
|
@ -32,22 +32,16 @@
|
|||
|
||||
IMPLEMENT_APP(Pcsx2App)
|
||||
|
||||
/*DEFINE_EVENT_TYPE( pxEVT_ReloadPlugins );
|
||||
DEFINE_EVENT_TYPE( pxEVT_OpenGsPanel );*/
|
||||
|
||||
DEFINE_EVENT_TYPE( pxEvt_FreezeThreadFinished );
|
||||
DEFINE_EVENT_TYPE( pxEvt_CoreThreadStatus );
|
||||
DEFINE_EVENT_TYPE( pxEvt_LoadPluginsComplete );
|
||||
DEFINE_EVENT_TYPE( pxEvt_PluginStatus );
|
||||
DEFINE_EVENT_TYPE( pxEvt_SysExecute );
|
||||
DEFINE_EVENT_TYPE( pxEvt_OpenModalDialog );
|
||||
DEFINE_EVENT_TYPE( pxEvt_InvokeMethod );
|
||||
DEFINE_EVENT_TYPE( pxEvt_LogicalVsync );
|
||||
|
||||
#include "Utilities/EventSource.inl"
|
||||
template class EventSource< IniInterface >;
|
||||
template class EventSource< AppEventType >;
|
||||
template class EventSource< PluginEventType >;
|
||||
DEFINE_EVENT_TYPE( pxEvt_OpenModalDialog );
|
||||
//DEFINE_EVENT_TYPE( pxEvt_OpenDialog_StuckThread );
|
||||
|
||||
bool UseAdminMode = false;
|
||||
wxDirName SettingsFolder;
|
||||
|
@ -69,7 +63,7 @@ static bool HandlePluginError( Exception::PluginError& ex )
|
|||
g_Conf->SysSettingsTabName = L"Plugins";
|
||||
|
||||
// fixme: Send a message to the panel to select the failed plugin.
|
||||
if( wxGetApp().IssueModalDialog( Dialogs::SysConfigDialog::GetNameStatic() ) == wxID_CANCEL )
|
||||
if( wxGetApp().IssueDialogAsModal( Dialogs::SysConfigDialog::GetNameStatic() ) == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
|
@ -79,13 +73,14 @@ static bool HandlePluginError( Exception::PluginError& ex )
|
|||
// And it's Thread Safe!
|
||||
void Pcsx2App::PostMenuAction( MenuIdentifiers menu_id ) const
|
||||
{
|
||||
if( m_MainFrame == NULL ) return;
|
||||
MainEmuFrame* mainFrame = GetMainFramePtr();
|
||||
if( mainFrame == NULL ) return;
|
||||
|
||||
wxCommandEvent joe( wxEVT_COMMAND_MENU_SELECTED, menu_id );
|
||||
if( wxThread::IsMain() )
|
||||
m_MainFrame->GetEventHandler()->ProcessEvent( joe );
|
||||
mainFrame->GetEventHandler()->ProcessEvent( joe );
|
||||
else
|
||||
m_MainFrame->GetEventHandler()->AddPendingEvent( joe );
|
||||
mainFrame->GetEventHandler()->AddPendingEvent( joe );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -100,25 +95,25 @@ class pxInvokeMethodEvent : public pxPingEvent
|
|||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxInvokeMethodEvent)
|
||||
|
||||
protected:
|
||||
FnType_AppMethod m_Method;
|
||||
FnPtr_AppMethod m_Method;
|
||||
|
||||
public:
|
||||
virtual ~pxInvokeMethodEvent() throw() { }
|
||||
virtual pxInvokeMethodEvent *Clone() const { return new pxInvokeMethodEvent(*this); }
|
||||
|
||||
explicit pxInvokeMethodEvent( int msgtype, FnType_AppMethod method=NULL, Semaphore* sema=NULL )
|
||||
explicit pxInvokeMethodEvent( int msgtype, FnPtr_AppMethod method=NULL, Semaphore* sema=NULL )
|
||||
: pxPingEvent( msgtype, sema )
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
|
||||
explicit pxInvokeMethodEvent( FnType_AppMethod method=NULL, Semaphore* sema=NULL )
|
||||
explicit pxInvokeMethodEvent( FnPtr_AppMethod method=NULL, Semaphore* sema=NULL )
|
||||
: pxPingEvent( pxEvt_InvokeMethod, sema )
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
|
||||
explicit pxInvokeMethodEvent( FnType_AppMethod method, Semaphore& sema )
|
||||
explicit pxInvokeMethodEvent( FnPtr_AppMethod method, Semaphore& sema )
|
||||
: pxPingEvent( pxEvt_InvokeMethod, &sema )
|
||||
{
|
||||
m_Method = method;
|
||||
|
@ -136,7 +131,7 @@ public:
|
|||
if( m_PostBack ) m_PostBack->Post();
|
||||
}
|
||||
|
||||
void SetMethod( FnType_AppMethod method )
|
||||
void SetMethod( FnPtr_AppMethod method )
|
||||
{
|
||||
m_Method = method;
|
||||
}
|
||||
|
@ -182,7 +177,9 @@ void Pcsx2App::PadKeyDispatch( const keyEvent& ev )
|
|||
// GS window while the PAD plugin is open, so send messages to the APP handler
|
||||
// only if *either* the GS or PAD plugins are in legacy mode.
|
||||
|
||||
if( m_gsFrame == NULL || (PADopen != NULL) )
|
||||
GSFrame* gsFrame = wxGetApp().GetGsFramePtr();
|
||||
|
||||
if( gsFrame == NULL || (PADopen != NULL) )
|
||||
{
|
||||
if( m_kevt.GetEventType() == wxEVT_KEY_DOWN )
|
||||
{
|
||||
|
@ -192,14 +189,15 @@ void Pcsx2App::PadKeyDispatch( const keyEvent& ev )
|
|||
}
|
||||
else
|
||||
{
|
||||
m_kevt.SetId( m_gsFrame->GetViewport()->GetId() );
|
||||
m_gsFrame->ProcessEvent( m_kevt );
|
||||
m_kevt.SetId( gsFrame->GetViewport()->GetId() );
|
||||
gsFrame->ProcessEvent( m_kevt );
|
||||
}
|
||||
}
|
||||
|
||||
void FramerateManager::Reset()
|
||||
{
|
||||
memzero( m_fpsqueue );
|
||||
m_initpause = FramerateQueueDepth;
|
||||
m_fpsqueue_tally = 0;
|
||||
m_fpsqueue_writepos = 0;
|
||||
Resume();
|
||||
|
@ -224,11 +222,13 @@ void FramerateManager::DoFrame()
|
|||
|
||||
m_fpsqueue[m_fpsqueue_writepos] = elapsed_time;
|
||||
m_fpsqueue_writepos = (m_fpsqueue_writepos + 1) % FramerateQueueDepth;
|
||||
if( m_initpause > 0 ) --m_initpause;
|
||||
}
|
||||
|
||||
double FramerateManager::GetFramerate() const
|
||||
{
|
||||
u32 ticks_per_frame = m_fpsqueue_tally / FramerateQueueDepth;
|
||||
if( m_initpause > (FramerateQueueDepth/2) ) return 0.0;
|
||||
u32 ticks_per_frame = m_fpsqueue_tally / (FramerateQueueDepth-m_initpause);
|
||||
return (double)GetTickFrequency() / (double)ticks_per_frame;
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ double FramerateManager::GetFramerate() const
|
|||
// times a second if not (ok, not quite, but you get the idea... I hope.)
|
||||
void Pcsx2App::LogicalVsync()
|
||||
{
|
||||
if( SelfMethodPost( &Pcsx2App::LogicalVsync ) ) return;
|
||||
if( PostMethodToMainThread( &Pcsx2App::LogicalVsync ) ) return;
|
||||
|
||||
if( !SysHasValidState() || g_plugins == NULL ) return;
|
||||
|
||||
|
@ -247,8 +247,8 @@ void Pcsx2App::LogicalVsync()
|
|||
|
||||
// Only call PADupdate here if we're using GSopen2. Legacy GSopen plugins have the
|
||||
// GS window belonging to the MTGS thread.
|
||||
if( (PADupdate != NULL) && (GSopen2 != NULL) && (m_gsFrame != NULL) )
|
||||
PADupdate(0);
|
||||
if( (PADupdate != NULL) && (GSopen2 != NULL) && (wxGetApp().GetGsFramePtr() != NULL) )
|
||||
PADupdate(0);
|
||||
|
||||
const keyEvent* ev = PADkeyEvent();
|
||||
|
||||
|
@ -295,7 +295,7 @@ void Pcsx2App::OnCoreThreadStatus( wxCommandEvent& evt )
|
|||
m_kevt.m_controlDown = false;
|
||||
m_kevt.m_altDown = false;
|
||||
|
||||
m_evtsrc_CoreThreadStatus.Dispatch( evt );
|
||||
m_evtsrc_CoreThreadStatus.Dispatch( status );
|
||||
ScopedBusyCursor::SetDefault( Cursor_NotBusy );
|
||||
CoreThread.RethrowException();
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ void Pcsx2App::OnOpenModalDialog( wxCommandEvent& evt )
|
|||
|
||||
MsgboxEventResult* evtres = (MsgboxEventResult*)evt.GetClientData();
|
||||
|
||||
wxWindowID result = IssueModalDialog( evt.GetString() );
|
||||
wxWindowID result = IssueDialogAsModal( evt.GetString() );
|
||||
|
||||
if( evtres != NULL )
|
||||
{
|
||||
|
@ -315,7 +315,34 @@ void Pcsx2App::OnOpenModalDialog( wxCommandEvent& evt )
|
|||
}
|
||||
}
|
||||
|
||||
int Pcsx2App::IssueModalDialog( const wxString& dlgName )
|
||||
void Pcsx2App::OnOpenDialog_StuckThread( wxCommandEvent& evt )
|
||||
{
|
||||
if( !pxAssert( evt.GetClientData() != NULL ) ) return;
|
||||
DoStuckThread( *(PersistentThread*)evt.GetClientData() );
|
||||
}
|
||||
|
||||
bool Pcsx2App::DoStuckThread( PersistentThread& stuck_thread )
|
||||
{
|
||||
if( !wxThread::IsMain() )
|
||||
{
|
||||
//PostCommand( &stuck_thread, pxEvt_OpenDialog_StuckThread );
|
||||
}
|
||||
|
||||
// Parent the dialog to the GS window if it belongs to PCSX2. If not
|
||||
// we should bind it to the Main window, and if that's not around, use NULL.
|
||||
|
||||
wxWindow* parent = GetGsFramePtr();
|
||||
if( parent == NULL )
|
||||
parent = GetMainFramePtr();
|
||||
|
||||
pxStuckThreadEvent evt( stuck_thread );
|
||||
return Msgbox::ShowModal( evt );
|
||||
}
|
||||
|
||||
// Opens the specified standard dialog as a modal dialog, or forces the an existing
|
||||
// instance of the dialog (ie, it's already open) to be modal. This is needed for
|
||||
// items which are
|
||||
int Pcsx2App::IssueDialogAsModal( const wxString& dlgName )
|
||||
{
|
||||
if( dlgName.IsEmpty() ) return wxID_CANCEL;
|
||||
|
||||
|
@ -409,6 +436,12 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
(handler->*func)(event);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::StartupAborted& ex ) // user-aborted, no popups needed.
|
||||
{
|
||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
Exit();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::BiosLoadFailed& ex )
|
||||
{
|
||||
wxDialogWithHelpers dialog( NULL, _("PS2 BIOS Error"), wxVERTICAL );
|
||||
|
@ -418,7 +451,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
if( dialog.ShowModal() == wxID_CANCEL )
|
||||
Console.Warning( "User denied option to re-configure BIOS." );
|
||||
|
||||
if( IssueModalDialog( Dialogs::BiosSelectorDialog::GetNameStatic() ) != wxID_CANCEL )
|
||||
if( IssueDialogAsModal( Dialogs::BiosSelectorDialog::GetNameStatic() ) != wxID_CANCEL )
|
||||
{
|
||||
SysExecute();
|
||||
}
|
||||
|
@ -455,7 +488,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::ThreadTimedOut& ex )
|
||||
catch( Exception::ThreadDeadlock& 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
|
||||
|
@ -505,14 +538,19 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
}
|
||||
}
|
||||
|
||||
static void __evt_fastcall OnStateSaveFinished( void* obj, wxCommandEvent& evt )
|
||||
class CancelCoreThreadWhenSaveStateDone : public IEventListener_CoreThread,
|
||||
public IDeletableObject
|
||||
{
|
||||
if( evt.GetInt() == CoreStatus_Resumed )
|
||||
public:
|
||||
virtual ~CancelCoreThreadWhenSaveStateDone() throw() {}
|
||||
|
||||
void OnCoreStatus_Resumed()
|
||||
{
|
||||
wxGetApp().PostMenuAction( MenuId_Exit );
|
||||
wxGetApp().Source_CoreThreadStatus().Remove( NULL, OnStateSaveFinished );
|
||||
Pcsx2App& myapp( wxGetApp() );
|
||||
myapp.DeleteObject( this );
|
||||
myapp.PostMenuAction( MenuId_Exit );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Common exit handler which can be called from any event (though really it should
|
||||
// be called only from CloseWindow handlers since that's the more appropriate way
|
||||
|
@ -524,13 +562,15 @@ bool Pcsx2App::PrepForExit( bool canCancel )
|
|||
{
|
||||
// If a savestate is saving, we should wait until it finishes. Otherwise the user
|
||||
// might lose data.
|
||||
|
||||
|
||||
if( StateCopy_IsBusy() )
|
||||
{
|
||||
Source_CoreThreadStatus().Add( NULL, OnStateSaveFinished );
|
||||
throw Exception::CancelEvent( "Savestate in progress, cannot close program (close event delayed)" );
|
||||
new CancelCoreThreadWhenSaveStateDone();
|
||||
throw Exception::CancelEvent( "Savestate in progress, close event delayed until action is complete." );
|
||||
}
|
||||
|
||||
CancelLoadingPlugins();
|
||||
|
||||
/*
|
||||
if( canCancel )
|
||||
{
|
||||
|
@ -548,27 +588,16 @@ bool Pcsx2App::PrepForExit( bool canCancel )
|
|||
}
|
||||
}*/
|
||||
|
||||
AppEventType toSend = AppStatus_Exiting;
|
||||
m_evtsrc_AppStatus.Dispatch( toSend );
|
||||
CleanupMess();
|
||||
DispatchEvent( AppStatus_Exiting );
|
||||
|
||||
// This should be called by OnExit(), but sometimes wxWidgets fails to call OnExit(), so
|
||||
// do it here just in case (no harm anyway -- OnExit is the next logical step after
|
||||
// CloseWindow returns true from the TopLevel window).
|
||||
CleanupRestartable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Pcsx2App::OnExit()
|
||||
{
|
||||
CleanupMess();
|
||||
|
||||
if( g_Conf )
|
||||
AppSaveSettings();
|
||||
|
||||
sMainFrame.RemoveEventHandler( &GetRecentIsoList() );
|
||||
|
||||
m_Resources = NULL;
|
||||
|
||||
return wxApp::OnExit();
|
||||
}
|
||||
|
||||
// This method generates debug assertions if the MainFrame handle is NULL (typically
|
||||
// indicating that PCSX2 is running in NoGUI mode, or that the main frame has been
|
||||
// closed). In most cases you'll want to use HasMainFrame() to test for thread
|
||||
|
@ -576,17 +605,22 @@ int Pcsx2App::OnExit()
|
|||
// is a matter of programmer preference).
|
||||
MainEmuFrame& Pcsx2App::GetMainFrame() const
|
||||
{
|
||||
pxAssume( ((uptr)GetTopWindow()) == ((uptr)m_MainFrame) );
|
||||
pxAssume( m_MainFrame != NULL );
|
||||
return *m_MainFrame;
|
||||
MainEmuFrame* mainFrame = GetMainFramePtr();
|
||||
|
||||
pxAssume( mainFrame != NULL );
|
||||
pxAssume( ((uptr)GetTopWindow()) == ((uptr)mainFrame) );
|
||||
return *mainFrame;
|
||||
}
|
||||
|
||||
GSFrame& Pcsx2App::GetGSFrame() const
|
||||
GSFrame& Pcsx2App::GetGsFrame() const
|
||||
{
|
||||
pxAssume( m_gsFrame != NULL );
|
||||
return *m_gsFrame;
|
||||
GSFrame* gsFrame = (GSFrame*)wxWindow::FindWindowById( m_id_GsFrame );
|
||||
|
||||
pxAssume( gsFrame != NULL );
|
||||
return *gsFrame;
|
||||
}
|
||||
|
||||
|
||||
void AppApplySettings( const AppConfig* oldconf )
|
||||
{
|
||||
AffinityAssert_AllowFromMain();
|
||||
|
@ -626,12 +660,67 @@ void AppApplySettings( const AppConfig* oldconf )
|
|||
}
|
||||
}
|
||||
|
||||
int toSend = 0;
|
||||
sApp.Source_SettingsApplied().Dispatch( toSend );
|
||||
sApp.DispatchEvent( AppStatus_SettingsApplied );
|
||||
suspend_core.Resume();
|
||||
}
|
||||
|
||||
static wxFileConfig _dud_config;
|
||||
class pxDudConfig : public wxConfigBase
|
||||
{
|
||||
protected:
|
||||
wxString m_empty;
|
||||
|
||||
public:
|
||||
virtual ~pxDudConfig() {}
|
||||
|
||||
virtual void SetPath(const wxString& ) {}
|
||||
virtual const wxString& GetPath() const { return m_empty; }
|
||||
|
||||
virtual bool GetFirstGroup(wxString& , long& ) const { return false; }
|
||||
virtual bool GetNextGroup (wxString& , long& ) const { return false; }
|
||||
virtual bool GetFirstEntry(wxString& , long& ) const { return false; }
|
||||
virtual bool GetNextEntry (wxString& , long& ) const { return false; }
|
||||
virtual size_t GetNumberOfEntries(bool ) const { return 0; }
|
||||
virtual size_t GetNumberOfGroups(bool ) const { return 0; }
|
||||
|
||||
virtual bool HasGroup(const wxString& ) const { return false; }
|
||||
virtual bool HasEntry(const wxString& ) const { return false; }
|
||||
|
||||
virtual bool Flush(bool ) { return false; }
|
||||
|
||||
virtual bool RenameEntry(const wxString&, const wxString& ) { return false; }
|
||||
|
||||
virtual bool RenameGroup(const wxString&, const wxString& ) { return false; }
|
||||
|
||||
virtual bool DeleteEntry(const wxString&, bool bDeleteGroupIfEmpty = true) { return false; }
|
||||
virtual bool DeleteGroup(const wxString& ) { return false; }
|
||||
virtual bool DeleteAll() { return false; }
|
||||
|
||||
protected:
|
||||
virtual bool DoReadString(const wxString& , wxString *) const { return false; }
|
||||
virtual bool DoReadLong(const wxString& , long *) const { return false; }
|
||||
|
||||
virtual bool DoWriteString(const wxString& , const wxString& ) { return false; }
|
||||
virtual bool DoWriteLong(const wxString& , long ) { return false; }
|
||||
};
|
||||
|
||||
static pxDudConfig _dud_config;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppIniSaver / AppIniLoader
|
||||
// --------------------------------------------------------------------------------------
|
||||
class AppIniSaver : public IniSaver
|
||||
{
|
||||
public:
|
||||
AppIniSaver();
|
||||
virtual ~AppIniSaver() throw() {}
|
||||
};
|
||||
|
||||
class AppIniLoader : public IniLoader
|
||||
{
|
||||
public:
|
||||
AppIniLoader();
|
||||
virtual ~AppIniLoader() throw() {}
|
||||
};
|
||||
|
||||
AppIniSaver::AppIniSaver()
|
||||
: IniSaver( (GetAppConfig() != NULL) ? *GetAppConfig() : _dud_config )
|
||||
|
@ -649,7 +738,7 @@ void AppLoadSettings()
|
|||
|
||||
AppIniLoader loader;
|
||||
g_Conf->LoadSave( loader );
|
||||
wxGetApp().Source_SettingsLoadSave().Dispatch( loader );
|
||||
sApp.DispatchEvent( loader );
|
||||
}
|
||||
|
||||
void AppSaveSettings()
|
||||
|
@ -658,9 +747,13 @@ void AppSaveSettings()
|
|||
|
||||
AppIniSaver saver;
|
||||
g_Conf->LoadSave( saver );
|
||||
wxGetApp().Source_SettingsLoadSave().Dispatch( saver );
|
||||
sApp.DispatchEvent( saver );
|
||||
}
|
||||
|
||||
// Invokes the specified Pcsx2App method, or posts the method to the main thread if the calling
|
||||
// thread is not Main. Action is blocking. For non-blocking method execution, use
|
||||
// PostMethodToMainThread.
|
||||
//
|
||||
// This function works something like setjmp/longjmp, in that the return value indicates if the
|
||||
// function actually executed the specified method or not.
|
||||
//
|
||||
|
@ -668,7 +761,7 @@ void AppSaveSettings()
|
|||
// FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
|
||||
// TRUE if the method was posted.
|
||||
//
|
||||
bool Pcsx2App::SelfMethodInvoke( FnType_AppMethod method )
|
||||
bool Pcsx2App::InvokeMethodOnMainThread( FnPtr_AppMethod method )
|
||||
{
|
||||
if( wxThread::IsMain() ) return false;
|
||||
|
||||
|
@ -680,7 +773,18 @@ bool Pcsx2App::SelfMethodInvoke( FnType_AppMethod method )
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Pcsx2App::SelfMethodPost( FnType_AppMethod method )
|
||||
// Invokes the specified Pcsx2App method, or posts the method to the main thread if the calling
|
||||
// thread is not Main. Action is non-blocking. For blocking method execution, use
|
||||
// InvokeMethodOnMainThread.
|
||||
//
|
||||
// This function works something like setjmp/longjmp, in that the return value indicates if the
|
||||
// function actually executed the specified method or not.
|
||||
//
|
||||
// Returns:
|
||||
// FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
|
||||
// TRUE if the method was posted.
|
||||
//
|
||||
bool Pcsx2App::PostMethodToMainThread( FnPtr_AppMethod method )
|
||||
{
|
||||
if( wxThread::IsMain() ) return false;
|
||||
pxInvokeMethodEvent evt( method );
|
||||
|
@ -688,20 +792,30 @@ bool Pcsx2App::SelfMethodPost( FnType_AppMethod method )
|
|||
return true;
|
||||
}
|
||||
|
||||
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
|
||||
// main thread.
|
||||
void Pcsx2App::PostMethod( FnPtr_AppMethod method )
|
||||
{
|
||||
pxInvokeMethodEvent evt( method );
|
||||
AddPendingEvent( evt );
|
||||
}
|
||||
|
||||
void Pcsx2App::OpenGsPanel()
|
||||
{
|
||||
if( SelfMethodInvoke( &Pcsx2App::OpenGsPanel ) ) return;
|
||||
if( InvokeMethodOnMainThread( &Pcsx2App::OpenGsPanel ) ) return;
|
||||
|
||||
if( m_gsFrame == NULL )
|
||||
GSFrame* gsFrame = GetGsFramePtr();
|
||||
if( gsFrame == NULL )
|
||||
{
|
||||
m_gsFrame = new GSFrame( m_MainFrame, L"PCSX2" );
|
||||
m_gsFrame->SetFocus();
|
||||
gsFrame = new GSFrame( GetMainFramePtr(), L"PCSX2" );
|
||||
gsFrame->SetFocus();
|
||||
m_id_GsFrame = gsFrame->GetId();
|
||||
}
|
||||
|
||||
pxAssumeDev( !GetPluginManager().IsOpen( PluginId_GS ), "GS Plugin must be closed prior to opening a new Gs Panel!" );
|
||||
|
||||
m_gsFrame->Show();
|
||||
pDsp = (uptr)m_gsFrame->GetViewport()->GetHandle();
|
||||
gsFrame->Show();
|
||||
pDsp = (uptr)gsFrame->GetViewport()->GetHandle();
|
||||
|
||||
// The "in the main window" quickie hack...
|
||||
//pDsp = (uptr)m_MainFrame->m_background.GetHandle();
|
||||
|
@ -709,11 +823,12 @@ void Pcsx2App::OpenGsPanel()
|
|||
|
||||
void Pcsx2App::CloseGsPanel()
|
||||
{
|
||||
if( SelfMethodInvoke( &Pcsx2App::CloseGsPanel ) ) return;
|
||||
if( InvokeMethodOnMainThread( &Pcsx2App::CloseGsPanel ) ) return;
|
||||
|
||||
if( m_gsFrame != NULL && CloseViewportWithPlugins )
|
||||
GSFrame* gsFrame = GetGsFramePtr();
|
||||
if( (gsFrame != NULL) && CloseViewportWithPlugins )
|
||||
{
|
||||
if( GSPanel* woot = m_gsFrame->GetViewport() )
|
||||
if( GSPanel* woot = gsFrame->GetViewport() )
|
||||
woot->Destroy();
|
||||
}
|
||||
}
|
||||
|
@ -721,22 +836,22 @@ void Pcsx2App::CloseGsPanel()
|
|||
void Pcsx2App::OnGsFrameClosed()
|
||||
{
|
||||
CoreThread.Suspend();
|
||||
m_gsFrame = NULL;
|
||||
m_id_GsFrame = wxID_ANY;
|
||||
}
|
||||
|
||||
void Pcsx2App::OnProgramLogClosed()
|
||||
{
|
||||
if( m_ProgramLogBox == NULL ) return;
|
||||
if( m_id_ProgramLogBox == wxID_ANY ) return;
|
||||
m_id_ProgramLogBox = wxID_ANY;
|
||||
DisableWindowLogging();
|
||||
m_ProgramLogBox = NULL;
|
||||
}
|
||||
|
||||
void Pcsx2App::OnMainFrameClosed()
|
||||
{
|
||||
// Nothing threaded depends on the mainframe (yet) -- it all passes through the main wxApp
|
||||
// message handler. But that might change in the future.
|
||||
if( m_MainFrame == NULL ) return;
|
||||
m_MainFrame = NULL;
|
||||
//if( m_id_MainFrame == wxID_ANY ) return;
|
||||
m_id_MainFrame = wxID_ANY;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -904,3 +1019,39 @@ SysCoreAllocations& GetSysCoreAlloc()
|
|||
{
|
||||
return *wxGetApp().m_CoreAllocs;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxStuckThreadEvent Implementation
|
||||
// --------------------------------------------------------------------------------------
|
||||
IMPLEMENT_DYNAMIC_CLASS( pxStuckThreadEvent, BaseMessageBoxEvent )
|
||||
|
||||
pxStuckThreadEvent::pxStuckThreadEvent()
|
||||
: BaseMessageBoxEvent()
|
||||
, m_Thread( *(PersistentThread*)NULL )
|
||||
{
|
||||
}
|
||||
|
||||
pxStuckThreadEvent::pxStuckThreadEvent( MsgboxEventResult& instdata, PersistentThread& thr )
|
||||
: BaseMessageBoxEvent( instdata, wxEmptyString )
|
||||
, m_Thread( thr )
|
||||
{
|
||||
}
|
||||
|
||||
pxStuckThreadEvent::pxStuckThreadEvent( PersistentThread& thr )
|
||||
: BaseMessageBoxEvent()
|
||||
, m_Thread( thr )
|
||||
{
|
||||
}
|
||||
|
||||
pxStuckThreadEvent::pxStuckThreadEvent( const pxStuckThreadEvent& src )
|
||||
: BaseMessageBoxEvent( src )
|
||||
, m_Thread( src.m_Thread )
|
||||
{
|
||||
}
|
||||
|
||||
int pxStuckThreadEvent::_DoDialog() const
|
||||
{
|
||||
return 1;
|
||||
//return Dialogs::StuckThreadDialog( m_Thread ).ShowModal();
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,8 @@ class BaseApplicableConfigPanel : public wxPanelWithHelpers
|
|||
protected:
|
||||
int m_OwnerPage;
|
||||
wxBookCtrlBase* m_OwnerBook;
|
||||
EventListenerBinding<int> m_Listener_SettingsApplied;
|
||||
|
||||
EventListenerHelper_AppStatus<BaseApplicableConfigPanel> m_AppStatusHelper;
|
||||
|
||||
public:
|
||||
virtual ~BaseApplicableConfigPanel() throw();
|
||||
|
@ -148,13 +149,16 @@ public:
|
|||
// If no exceptions are thrown, then the operation is assumed a success. :)
|
||||
virtual void Apply()=0;
|
||||
|
||||
// This method is bound to the ApplySettings event from the PCSX2 app manager.
|
||||
// Mandatory override: As a rule for proper interface design, all deriving classes need
|
||||
// to implement this function. There's no implementation of an options/settings panel
|
||||
// that does not heed the changes of application status/settings changes. ;)
|
||||
//
|
||||
// Note: This method *will* be called automatically after a successful Apply, but will not
|
||||
// be called after a failed Apply (canceled due to error).
|
||||
virtual void OnSettingsChanged()=0;
|
||||
virtual void AppStatusEvent_OnSettingsApplied()=0;
|
||||
|
||||
protected:
|
||||
static void __evt_fastcall OnSettingsApplied( void* obj, int& evt );
|
||||
virtual void AppStatusEvent_OnSettingsLoadSave( const AppSettingsEventInfo& ) {}
|
||||
virtual void AppStatusEvent_OnExit() {}
|
||||
|
||||
void Init();
|
||||
};
|
||||
|
|
|
@ -695,14 +695,19 @@ void ConsoleLogFrame::DoFlushQueue()
|
|||
|
||||
ConsoleLogFrame* Pcsx2App::GetProgramLog()
|
||||
{
|
||||
return m_ProgramLogBox;
|
||||
return (ConsoleLogFrame*) wxWindow::FindWindowById( m_id_ProgramLogBox );
|
||||
}
|
||||
|
||||
const ConsoleLogFrame* Pcsx2App::GetProgramLog() const
|
||||
{
|
||||
return (const ConsoleLogFrame*) wxWindow::FindWindowById( m_id_ProgramLogBox );
|
||||
}
|
||||
|
||||
void Pcsx2App::ProgramLog_PostEvent( wxEvent& evt )
|
||||
{
|
||||
// New console log object model makes this check obsolete:
|
||||
//if( m_ProgramLogBox == NULL ) return;
|
||||
m_ProgramLogBox->GetEventHandler()->AddPendingEvent( evt );
|
||||
GetProgramLog()->GetEventHandler()->AddPendingEvent( evt );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -828,17 +833,20 @@ static const IConsoleWriter ConsoleWriter_WindowAndFile =
|
|||
|
||||
void Pcsx2App::EnableAllLogging() const
|
||||
{
|
||||
const bool logBoxOpen = (GetProgramLog() != NULL);
|
||||
|
||||
if( emuLog )
|
||||
Console_SetActiveHandler( (m_ProgramLogBox!=NULL) ? (IConsoleWriter&)ConsoleWriter_WindowAndFile : (IConsoleWriter&)ConsoleWriter_File );
|
||||
Console_SetActiveHandler( logBoxOpen ? (IConsoleWriter&)ConsoleWriter_WindowAndFile : (IConsoleWriter&)ConsoleWriter_File );
|
||||
else
|
||||
Console_SetActiveHandler( (m_ProgramLogBox!=NULL) ? (IConsoleWriter&)ConsoleWriter_Window : (IConsoleWriter&)ConsoleWriter_Stdout );
|
||||
Console_SetActiveHandler( logBoxOpen ? (IConsoleWriter&)ConsoleWriter_Window : (IConsoleWriter&)ConsoleWriter_Stdout );
|
||||
}
|
||||
|
||||
// Used to disable the emuLog disk logger, typically used when disabling or re-initializing the
|
||||
// emuLog file handle. Call SetConsoleLogging to re-enable the disk logger when finished.
|
||||
void Pcsx2App::DisableDiskLogging() const
|
||||
{
|
||||
Console_SetActiveHandler( (m_ProgramLogBox!=NULL) ? (IConsoleWriter&)ConsoleWriter_Window : (IConsoleWriter&)ConsoleWriter_Stdout );
|
||||
const bool logBoxOpen = (GetProgramLog() != NULL);
|
||||
Console_SetActiveHandler( logBoxOpen ? (IConsoleWriter&)ConsoleWriter_Window : (IConsoleWriter&)ConsoleWriter_Stdout );
|
||||
|
||||
// Semi-hack: It's possible, however very unlikely, that a secondary thread could attempt
|
||||
// to write to the logfile just before we disable logging, and would thus have a pending write
|
||||
|
|
|
@ -89,12 +89,9 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// pxLogTextCtrl
|
||||
// --------------------------------------------------------------------------------------
|
||||
class pxLogTextCtrl : public wxTextCtrl
|
||||
class pxLogTextCtrl : public wxTextCtrl, public IEventListener_CoreThread, public IEventListener_Plugins
|
||||
{
|
||||
protected:
|
||||
CmdEvt_ListenerBinding m_Listener_CoreThreadStatus;
|
||||
EventListenerBinding<PluginEventType> m_Listener_CorePluginStatus;
|
||||
|
||||
#ifdef __WXMSW__
|
||||
int m_win32_LinesPerPage;
|
||||
int m_win32_LinesPerScroll;
|
||||
|
@ -116,9 +113,9 @@ protected:
|
|||
virtual void OnThumbTrack(wxScrollWinEvent& event);
|
||||
virtual void OnThumbRelease(wxScrollWinEvent& event);
|
||||
virtual void OnResize( wxSizeEvent& evt );
|
||||
|
||||
static void __evt_fastcall OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt );
|
||||
static void __evt_fastcall OnCorePluginStatusChanged( void* obj, PluginEventType& evt );
|
||||
|
||||
void DispatchEvent( const CoreThreadStatus& status );
|
||||
void DispatchEvent( const PluginEventType& evt );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -67,6 +67,7 @@ protected:
|
|||
virtual void OnDoubleClicked( wxCommandEvent& evt );
|
||||
};
|
||||
|
||||
|
||||
namespace Dialogs
|
||||
{
|
||||
class AboutBoxDialog: public wxDialogWithHelpers
|
||||
|
@ -114,8 +115,41 @@ namespace Dialogs
|
|||
public:
|
||||
AssertionDialog( const wxString& text, const wxString& stacktrace );
|
||||
virtual ~AssertionDialog() throw() {}
|
||||
};
|
||||
|
||||
// There are two types of stuck threads:
|
||||
// * Threads stuck on any action that is not a cancellation.
|
||||
// * Threads stuck trying to cancel.
|
||||
//
|
||||
// The former means we can provide a "cancel" action for the user, which would itself
|
||||
// open a new dialog in the latter category. The latter means that there's really nothing
|
||||
// we can do, since pthreads API provides no good way for killing threads. The only
|
||||
// valid options for the user in that case is to either wait (boring!) or kill the
|
||||
// process (awesome!).
|
||||
|
||||
enum StuckThreadActionType
|
||||
{
|
||||
// Allows the user to attempt a cancellation of a stuck thread. This should only be
|
||||
// used on threads which are not already stuck during a cancellation action (ie, suspension
|
||||
// or other job requests). Also, if the running thread is known to not have any
|
||||
// cancellation points then this shouldn't be used either.
|
||||
StacT_TryCancel,
|
||||
|
||||
// Allows the user to kill the entire process for a stuck thread. Use this for any
|
||||
// thread which has failed to cancel in a reasonable timeframe, or for any stuck action
|
||||
// if the thread is known to have no cancellation points.
|
||||
StacT_KillProcess,
|
||||
};
|
||||
|
||||
class StuckThreadDialog : public wxDialogWithHelpers,
|
||||
public EventListener_Thread
|
||||
{
|
||||
public:
|
||||
StuckThreadDialog( wxWindow* parent, StuckThreadActionType action, Threading::PersistentThread& stuck_thread );
|
||||
virtual ~StuckThreadDialog() throw() {}
|
||||
|
||||
|
||||
protected:
|
||||
void OnThreadCleanup();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* 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;
|
||||
using namespace Threading;
|
||||
|
||||
Dialogs::StuckThreadDialog::StuckThreadDialog( wxWindow* parent, StuckThreadActionType action, PersistentThread& stuck_thread )
|
||||
: wxDialogWithHelpers( parent, _("PCSX2 Thread is not responding"), wxVERTICAL )
|
||||
{
|
||||
//m_idealWidth = 720;
|
||||
|
||||
stuck_thread.AddListener( this );
|
||||
|
||||
*this += Heading( wxsFormat(
|
||||
pxE( ".Dialog:StuckThread:Heading",
|
||||
L"The thread '%s' is not responding. It could be deadlocked, or it might "
|
||||
L"just be running *really* slowly."
|
||||
),
|
||||
stuck_thread.GetName()
|
||||
) );
|
||||
|
||||
|
||||
*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().Cancel().Custom(L"Wait") ) | StdCenter();
|
||||
|
||||
if( wxWindow* idyes = FindWindowById( wxID_YES ) )
|
||||
idyes->SetFocus();
|
||||
}
|
||||
|
||||
void Dialogs::StuckThreadDialog::OnThreadCleanup()
|
||||
{
|
||||
}
|
|
@ -22,6 +22,9 @@
|
|||
|
||||
void GSPanel::InitDefaultAccelerators()
|
||||
{
|
||||
// Note! These don't really work yet due to some hacks to get things working for
|
||||
// old legacy PAD plugins. (the global accelerator tables are used instead) --air
|
||||
|
||||
typedef KeyAcceleratorCode AAC;
|
||||
|
||||
m_Accels.Map( AAC( WXK_F1 ), "States_FreezeCurrentSlot" );
|
||||
|
@ -46,7 +49,6 @@ void GSPanel::InitDefaultAccelerators()
|
|||
|
||||
GSPanel::GSPanel( wxWindow* parent )
|
||||
: wxWindow()
|
||||
, m_Listener_SettingsApplied ( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
|
||||
, m_HideMouseTimer( this )
|
||||
{
|
||||
m_CursorShown = true;
|
||||
|
@ -211,15 +213,7 @@ void GSPanel::OnFocusLost( wxFocusEvent& evt )
|
|||
DoShowMouse();
|
||||
}
|
||||
|
||||
void __evt_fastcall GSPanel::OnSettingsApplied( void* obj, int& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
GSPanel* panel = (GSPanel*)obj;
|
||||
|
||||
panel->DoSettingsApplied();
|
||||
}
|
||||
|
||||
void GSPanel::DoSettingsApplied()
|
||||
void GSPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
if( IsBeingDeleted() ) return;
|
||||
DoResize();
|
||||
|
@ -237,7 +231,6 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title)
|
|||
(g_Conf->GSWindow.DisableResizeBorders ? 0 : wxRESIZE_BORDER) | wxCAPTION | wxCLIP_CHILDREN |
|
||||
wxSYSTEM_MENU | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX
|
||||
)
|
||||
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
|
||||
, m_timer_UpdateTitle( this )
|
||||
{
|
||||
SetIcons( wxGetApp().GetIconBundle() );
|
||||
|
@ -246,14 +239,18 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title)
|
|||
SetBackgroundColour( *wxBLACK );
|
||||
|
||||
wxStaticText* label = new wxStaticText( this, wxID_ANY, _("GS Output is Disabled!") );
|
||||
label->SetName(L"OutputDisabledLabel");
|
||||
m_id_OutputDisabled = label->GetId();
|
||||
label->SetFont( *new wxFont( 20, wxDEFAULT, wxNORMAL, wxBOLD ) );
|
||||
label->SetForegroundColour( *wxWHITE );
|
||||
label->Show( EmuConfig.GS.DisableOutput );
|
||||
|
||||
GSPanel* gsPanel = new GSPanel( this );
|
||||
gsPanel->Show( !EmuConfig.GS.DisableOutput );
|
||||
m_gspanel_id = gsPanel->GetId();
|
||||
m_id_gspanel = gsPanel->GetId();
|
||||
|
||||
// TODO -- Implement this GS window status window! Whee.
|
||||
// (main concern is retaining proper client window sizes when closing/re-opening the window).
|
||||
//m_statusbar = CreateStatusBar( 2 );
|
||||
|
||||
//Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSFrame::OnCloseWindow) );
|
||||
Connect( wxEVT_MOVE, wxMoveEventHandler (GSFrame::OnMove) );
|
||||
|
@ -267,6 +264,11 @@ GSFrame::~GSFrame() throw()
|
|||
{
|
||||
}
|
||||
|
||||
wxStaticText* GSFrame::GetLabel_OutputDisabled() const
|
||||
{
|
||||
return (wxStaticText*)FindWindowById( m_id_OutputDisabled );
|
||||
}
|
||||
|
||||
// overrides base Show behavior.
|
||||
bool GSFrame::Show( bool shown )
|
||||
{
|
||||
|
@ -277,12 +279,15 @@ bool GSFrame::Show( bool shown )
|
|||
if( gsPanel == NULL || gsPanel->IsBeingDeleted() )
|
||||
{
|
||||
gsPanel = new GSPanel( this );
|
||||
m_gspanel_id = gsPanel->GetId();
|
||||
m_id_gspanel = gsPanel->GetId();
|
||||
}
|
||||
|
||||
gsPanel->Show( !EmuConfig.GS.DisableOutput );
|
||||
gsPanel->DoResize();
|
||||
gsPanel->SetFocus();
|
||||
|
||||
if( wxStaticText* label = GetLabel_OutputDisabled() )
|
||||
label->Show( !EmuConfig.GS.DisableOutput );
|
||||
|
||||
m_timer_UpdateTitle.Start( 333 );
|
||||
}
|
||||
|
@ -294,27 +299,19 @@ bool GSFrame::Show( bool shown )
|
|||
return _parent::Show( shown );
|
||||
}
|
||||
|
||||
void __evt_fastcall GSFrame::OnSettingsApplied( void* obj, int& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
GSFrame* frame = (GSFrame*)obj;
|
||||
|
||||
frame->DoSettingsApplied();
|
||||
}
|
||||
|
||||
void GSFrame::DoSettingsApplied()
|
||||
void GSFrame::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
if( IsBeingDeleted() ) return;
|
||||
ShowFullScreen( g_Conf->GSWindow.DefaultToFullscreen );
|
||||
Show( !g_Conf->GSWindow.CloseOnEsc || ((g_plugins==NULL) || !SysHasValidState()) );
|
||||
|
||||
if( wxStaticText* label = (wxStaticText*)FindWindowByName(L"OutputDisabledLabel") )
|
||||
if( wxStaticText* label = GetLabel_OutputDisabled() )
|
||||
label->Show( !EmuConfig.GS.DisableOutput );
|
||||
}
|
||||
|
||||
GSPanel* GSFrame::GetViewport()
|
||||
{
|
||||
return (GSPanel*)FindWindowById( m_gspanel_id );
|
||||
return (GSPanel*)FindWindowById( m_id_gspanel );
|
||||
}
|
||||
|
||||
void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
|
||||
|
|
|
@ -111,7 +111,8 @@ void MainEmuFrame::OnMoveAround( wxMoveEvent& evt )
|
|||
if( g_Conf->ProgLogBox.AutoDock )
|
||||
{
|
||||
g_Conf->ProgLogBox.DisplayPosition = GetRect().GetTopRight();
|
||||
wxGetApp().GetProgramLog()->SetPosition( g_Conf->ProgLogBox.DisplayPosition );
|
||||
if( ConsoleLogFrame* proglog = wxGetApp().GetProgramLog() )
|
||||
proglog->SetPosition( g_Conf->ProgLogBox.DisplayPosition );
|
||||
}
|
||||
|
||||
//evt.Skip();
|
||||
|
@ -135,6 +136,7 @@ void MainEmuFrame::ConnectMenus()
|
|||
ConnectMenu( MenuId_Config_SysSettings, Menu_ConfigSettings_Click );
|
||||
ConnectMenu( MenuId_Config_AppSettings, Menu_AppSettings_Click );
|
||||
ConnectMenu( MenuId_Config_BIOS, Menu_SelectBios_Click );
|
||||
ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_Click );
|
||||
|
||||
ConnectMenu( MenuId_Config_Multitap0Toggle, Menu_MultitapToggle_Click );
|
||||
ConnectMenu( MenuId_Config_Multitap1Toggle, Menu_MultitapToggle_Click );
|
||||
|
@ -193,44 +195,30 @@ void MainEmuFrame::InitLogBoxPosition( AppConfig::ConsoleLogOptions& conf )
|
|||
}
|
||||
}
|
||||
|
||||
void __evt_fastcall MainEmuFrame::OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt )
|
||||
void MainEmuFrame::DispatchEvent( const PluginEventType& plugin_evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
if( !pxAssertMsg( mframe->GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return;
|
||||
if( !pxAssertMsg( GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return;
|
||||
|
||||
mframe->ApplyCoreStatus();
|
||||
//ApplyCoreStatus();
|
||||
ApplyPluginStatus();
|
||||
}
|
||||
|
||||
void __evt_fastcall MainEmuFrame::OnCorePluginStatusChanged( void* obj, PluginEventType& evt )
|
||||
void MainEmuFrame::DispatchEvent( const CoreThreadStatus& status )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
if( (evt != PluginsEvt_Loaded) && (evt != PluginsEvt_Unloaded) ) return; // everything else we don't care about
|
||||
|
||||
MainEmuFrame& mframe = *(MainEmuFrame*)obj;
|
||||
if( !pxAssertMsg( mframe.GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return;
|
||||
|
||||
//mframe.ApplyCoreStatus();
|
||||
mframe.ApplyPluginStatus();
|
||||
if( !pxAssertMsg( GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return;
|
||||
ApplyCoreStatus();
|
||||
}
|
||||
|
||||
void __evt_fastcall MainEmuFrame::OnSettingsApplied( void* obj, int& evt )
|
||||
void MainEmuFrame::AppStatusEvent_OnSettingsLoadSave()
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
if( !pxAssertMsg( mframe->GetMenuBar()!=NULL, "Mainframe menu bar is NULL!" ) ) return;
|
||||
|
||||
mframe->ApplySettings();
|
||||
}
|
||||
|
||||
void __evt_fastcall MainEmuFrame::OnSettingsLoadSave( void* obj, IniInterface& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
//MainEmuFrame* mframe = (MainEmuFrame*)obj;
|
||||
|
||||
// nothing to do here right now.
|
||||
}
|
||||
|
||||
void MainEmuFrame::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
ApplySettings();
|
||||
}
|
||||
|
||||
static int GetPluginMenuId_Settings( PluginsEnum_t pid )
|
||||
{
|
||||
return MenuId_PluginBase_Settings + ((int)pid * PluginMenuId_Interval);
|
||||
|
@ -265,11 +253,9 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
|
|||
, m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) )
|
||||
, m_MenuItem_Console_Stdio( *new wxMenuItem( &m_menuMisc, MenuId_Console_Stdio, L"Console to Stdio", wxEmptyString, wxITEM_CHECK ) )
|
||||
|
||||
, m_Listener_CoreThreadStatus ( wxGetApp().Source_CoreThreadStatus(), CmdEvt_Listener ( this, OnCoreThreadStatusChanged ) )
|
||||
, m_Listener_CorePluginStatus ( wxGetApp().Source_CorePluginStatus(), EventListener<PluginEventType> ( this, OnCorePluginStatusChanged ) )
|
||||
, m_Listener_SettingsApplied ( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
|
||||
, m_Listener_SettingsLoadSave ( wxGetApp().Source_SettingsLoadSave(), EventListener<IniInterface> ( this, OnSettingsLoadSave ) )
|
||||
{
|
||||
m_RestartEmuOnDelete = false;
|
||||
|
||||
for( int i=0; i<PluginId_Count; ++i )
|
||||
m_PluginMenuPacks[i].Populate( (PluginsEnum_t)i );
|
||||
|
||||
|
@ -410,7 +396,7 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
|
|||
m_menuConfig.Append(MenuId_Config_Multitap1Toggle, _("Multitap 2"), wxEmptyString, wxITEM_CHECK );
|
||||
|
||||
m_menuConfig.AppendSeparator();
|
||||
m_menuConfig.Append(MenuId_Config_ResetAll, _("Reset all..."),
|
||||
m_menuConfig.Append(MenuId_Config_ResetAll, _("Clear all settings..."),
|
||||
_("Clears all PCSX2 settings and re-runs the startup wizard."));
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -456,6 +442,13 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
|
|||
MainEmuFrame::~MainEmuFrame() throw()
|
||||
{
|
||||
m_menuCDVD.Remove( MenuId_IsoSelector );
|
||||
|
||||
if( m_RestartEmuOnDelete )
|
||||
{
|
||||
sApp.SetExitOnFrameDelete( false );
|
||||
sApp.PostMethod( &Pcsx2App::DetectCpuAndUserMode );
|
||||
sApp.WipeUserModeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -33,13 +33,12 @@ extern LimiterModeType g_LimiterMode;
|
|||
// --------------------------------------------------------------------------------------
|
||||
// GSPanel
|
||||
// --------------------------------------------------------------------------------------
|
||||
class GSPanel : public wxWindow
|
||||
class GSPanel : public wxWindow, public IEventListener_AppStatus
|
||||
{
|
||||
typedef wxWindow _parent;
|
||||
|
||||
protected:
|
||||
AcceleratorDictionary m_Accels;
|
||||
EventListenerBinding<int> m_Listener_SettingsApplied;
|
||||
wxTimer m_HideMouseTimer;
|
||||
bool m_CursorShown;
|
||||
bool m_HasFocus;
|
||||
|
@ -52,7 +51,7 @@ public:
|
|||
void DoShowMouse();
|
||||
|
||||
protected:
|
||||
static void __evt_fastcall OnSettingsApplied( void* obj, int& evt );
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
virtual WXLRESULT MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam);
|
||||
|
@ -60,8 +59,6 @@ protected:
|
|||
|
||||
void InitDefaultAccelerators();
|
||||
|
||||
void DoSettingsApplied();
|
||||
|
||||
void OnCloseWindow( wxCloseEvent& evt );
|
||||
void OnResize(wxSizeEvent& event);
|
||||
void OnShowMouse( wxMouseEvent& evt );
|
||||
|
@ -74,15 +71,16 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// GSFrame
|
||||
// --------------------------------------------------------------------------------------
|
||||
class GSFrame : public wxFrame
|
||||
class GSFrame : public wxFrame, public IEventListener_AppStatus
|
||||
{
|
||||
typedef wxFrame _parent;
|
||||
|
||||
protected:
|
||||
EventListenerBinding<int> m_Listener_SettingsApplied;
|
||||
wxTimer m_timer_UpdateTitle;
|
||||
wxWindowID m_gspanel_id;
|
||||
wxWindowID m_id_gspanel;
|
||||
wxWindowID m_id_OutputDisabled;
|
||||
wxStaticText* m_label_Disabled;
|
||||
wxStatusBar* m_statusbar;
|
||||
|
||||
public:
|
||||
GSFrame(wxWindow* parent, const wxString& title);
|
||||
|
@ -91,6 +89,7 @@ public:
|
|||
GSPanel* GetViewport();
|
||||
|
||||
bool Show( bool shown=true );
|
||||
wxStaticText* GetLabel_OutputDisabled() const;
|
||||
|
||||
protected:
|
||||
void OnMove( wxMoveEvent& evt );
|
||||
|
@ -98,9 +97,7 @@ protected:
|
|||
void OnActivate( wxActivateEvent& evt );
|
||||
void OnUpdateTitle( wxTimerEvent& evt );
|
||||
|
||||
void DoSettingsApplied();
|
||||
|
||||
static void __evt_fastcall OnSettingsApplied( void* obj, int& evt );
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
struct PluginMenuAddition
|
||||
|
@ -159,9 +156,14 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// MainEmuFrame
|
||||
// --------------------------------------------------------------------------------------
|
||||
class MainEmuFrame : public wxFrame
|
||||
class MainEmuFrame : public wxFrame,
|
||||
public virtual IEventListener_Plugins,
|
||||
public virtual IEventListener_CoreThread,
|
||||
public virtual IEventListener_AppStatus
|
||||
{
|
||||
protected:
|
||||
bool m_RestartEmuOnDelete;
|
||||
|
||||
wxStatusBar& m_statusbar;
|
||||
wxStaticBitmap m_background;
|
||||
|
||||
|
@ -182,10 +184,10 @@ protected:
|
|||
|
||||
PerPluginMenuInfo m_PluginMenuPacks[PluginId_Count];
|
||||
|
||||
CmdEvt_ListenerBinding m_Listener_CoreThreadStatus;
|
||||
EventListenerBinding<PluginEventType> m_Listener_CorePluginStatus;
|
||||
EventListenerBinding<int> m_Listener_SettingsApplied;
|
||||
EventListenerBinding<IniInterface> m_Listener_SettingsLoadSave;
|
||||
virtual void DispatchEvent( const PluginEventType& plugin_evt );
|
||||
virtual void DispatchEvent( const CoreThreadStatus& status );
|
||||
virtual void AppStatusEvent_OnSettingsLoadSave();
|
||||
virtual void AppStatusEvent_OnSettingsApplied();
|
||||
|
||||
public:
|
||||
MainEmuFrame(wxWindow* parent, const wxString& title);
|
||||
|
@ -197,11 +199,6 @@ public:
|
|||
void UpdateIsoSrcSelection();
|
||||
|
||||
protected:
|
||||
static void __evt_fastcall OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt );
|
||||
static void __evt_fastcall OnCorePluginStatusChanged( void* obj, PluginEventType& evt );
|
||||
static void __evt_fastcall OnSettingsApplied( void* obj, int& evt );
|
||||
static void __evt_fastcall OnSettingsLoadSave( void* obj, IniInterface& evt );
|
||||
|
||||
void ApplySettings();
|
||||
void ApplyCoreStatus();
|
||||
void ApplyPluginStatus();
|
||||
|
@ -218,6 +215,7 @@ protected:
|
|||
void Menu_ConfigSettings_Click(wxCommandEvent &event);
|
||||
void Menu_AppSettings_Click(wxCommandEvent &event);
|
||||
void Menu_SelectBios_Click(wxCommandEvent &event);
|
||||
void Menu_ResetAllSettings_Click(wxCommandEvent &event);
|
||||
|
||||
void Menu_IsoBrowse_Click(wxCommandEvent &event);
|
||||
void Menu_SkipBiosToggle_Click(wxCommandEvent &event);
|
||||
|
|
|
@ -54,6 +54,87 @@ void MainEmuFrame::Menu_SelectBios_Click(wxCommandEvent &event)
|
|||
AppOpenDialog<BiosSelectorDialog>( this );
|
||||
}
|
||||
|
||||
|
||||
static void WipeSettings()
|
||||
{
|
||||
UnloadPlugins();
|
||||
wxGetApp().CleanupRestartable();
|
||||
wxGetApp().CleanupResources();
|
||||
|
||||
wxRemoveFile( GetSettingsFilename() );
|
||||
|
||||
// FIXME: wxRmdir doesn't seem to work here for some reason (possible file sharing issue
|
||||
// with a plugin that leaves a file handle dangling maybe?). But deleting the inis folder
|
||||
// manually from explorer does work. Can't think of a good work-around at the moment. --air
|
||||
|
||||
//wxRmdir( GetSettingsFolder().ToString() );
|
||||
}
|
||||
|
||||
class RestartEverything_WhenCoreThreadStops : public IEventListener_CoreThread,
|
||||
public virtual IDeletableObject
|
||||
{
|
||||
public:
|
||||
RestartEverything_WhenCoreThreadStops() {}
|
||||
virtual ~RestartEverything_WhenCoreThreadStops() throw() {}
|
||||
|
||||
protected:
|
||||
virtual void OnCoreStatus_Stopped()
|
||||
{
|
||||
wxGetApp().DeleteObject( this );
|
||||
WipeSettings();
|
||||
}
|
||||
};
|
||||
|
||||
class CancelCoreThread_WhenSaveStateDone : public IEventListener_CoreThread,
|
||||
public IDeletableObject
|
||||
{
|
||||
public:
|
||||
virtual ~CancelCoreThread_WhenSaveStateDone() throw() {}
|
||||
|
||||
void OnCoreStatus_Resumed()
|
||||
{
|
||||
wxGetApp().DeleteObject( this );
|
||||
CoreThread.Cancel();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void MainEmuFrame::Menu_ResetAllSettings_Click(wxCommandEvent &event)
|
||||
{
|
||||
if( IsBeingDeleted() || m_RestartEmuOnDelete ) return;
|
||||
|
||||
ScopedCoreThreadSuspend suspender;
|
||||
if( !Msgbox::OkCancel(
|
||||
pxE( ".Popup Warning:DeleteSettings",
|
||||
L"WARNING!! This option will delete *ALL* settings for PCSX2 and force PCSX2 to restart, losing any current emulation progress. Are you absolutely sure?"
|
||||
L"\n\n(note: settings for plugins are unaffected)"
|
||||
),
|
||||
_("Reset all settings?") ) )
|
||||
{
|
||||
suspender.Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
m_RestartEmuOnDelete = true;
|
||||
Destroy();
|
||||
|
||||
if( CoreThread.IsRunning() )
|
||||
{
|
||||
new RestartEverything_WhenCoreThreadStops();
|
||||
|
||||
if( StateCopy_IsBusy() )
|
||||
{
|
||||
new CancelCoreThread_WhenSaveStateDone();
|
||||
throw Exception::CancelEvent( "Savestate in progress, app restart event delayed until action is complete." );
|
||||
}
|
||||
CoreThread.Cancel();
|
||||
}
|
||||
else
|
||||
{
|
||||
WipeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_CdvdSource_Click( wxCommandEvent &event )
|
||||
{
|
||||
CDVD_SourceType newSource = CDVDsrc_NoDisc;
|
||||
|
|
|
@ -147,18 +147,18 @@ int pxMessageBoxEvent::_DoDialog() const
|
|||
IMPLEMENT_DYNAMIC_CLASS( pxAssertionEvent, BaseMessageBoxEvent )
|
||||
|
||||
pxAssertionEvent::pxAssertionEvent()
|
||||
: BaseMessageBoxEvent( pxEvt_Assertion )
|
||||
: BaseMessageBoxEvent( )
|
||||
{
|
||||
}
|
||||
|
||||
pxAssertionEvent::pxAssertionEvent( MsgboxEventResult& instdata, const wxString& content, const wxString& trace )
|
||||
: BaseMessageBoxEvent( pxEvt_Assertion )
|
||||
: BaseMessageBoxEvent( instdata, content )
|
||||
, m_Stacktrace( trace )
|
||||
{
|
||||
}
|
||||
|
||||
pxAssertionEvent::pxAssertionEvent( const wxString& content, const wxString& trace )
|
||||
: BaseMessageBoxEvent( pxEvt_Assertion, content )
|
||||
: BaseMessageBoxEvent( content )
|
||||
, m_Stacktrace( trace )
|
||||
{
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ int pxAssertionEvent::_DoDialog() const
|
|||
|
||||
namespace Msgbox
|
||||
{
|
||||
static int ThreadedMessageBox( BaseMessageBoxEvent& evt )
|
||||
int ShowModal( BaseMessageBoxEvent& evt )
|
||||
{
|
||||
MsgboxEventResult instdat;
|
||||
evt.SetInstData( instdat );
|
||||
|
@ -207,7 +207,7 @@ namespace Msgbox
|
|||
return instdat.result;
|
||||
}
|
||||
|
||||
static int ThreadedMessageBox( const wxString& title, const wxString& content, const MsgButtons& buttons )
|
||||
static int ShowModal( 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.
|
||||
|
@ -228,7 +228,7 @@ namespace Msgbox
|
|||
if( wxThread::IsMain() )
|
||||
pxMessageDialog( caption, text, buttons );
|
||||
else
|
||||
ThreadedMessageBox( caption, text, buttons );
|
||||
ShowModal( caption, text, buttons );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ namespace Msgbox
|
|||
}
|
||||
else
|
||||
{
|
||||
return wxID_OK == ThreadedMessageBox( caption, text, buttons );
|
||||
return wxID_OK == ShowModal( caption, text, buttons );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,13 +258,13 @@ namespace Msgbox
|
|||
}
|
||||
else
|
||||
{
|
||||
return wxID_YES == ThreadedMessageBox( caption, text, buttons );
|
||||
return wxID_YES == ShowModal( caption, text, buttons );
|
||||
}
|
||||
}
|
||||
|
||||
int Assertion( const wxString& text, const wxString& stacktrace )
|
||||
{
|
||||
pxAssertionEvent tevt( text, stacktrace );
|
||||
return ThreadedMessageBox( tevt );
|
||||
return ShowModal( tevt );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <wx/filepicker.h>
|
||||
#include <wx/listbox.h>
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
Panels::BaseSelectorPanel::BaseSelectorPanel( wxWindow* parent )
|
||||
: BaseApplicableConfigPanel( parent, wxVERTICAL )
|
||||
|
@ -127,7 +126,7 @@ void Panels::BiosSelectorPanel::Apply()
|
|||
g_Conf->BaseFilenames.Bios = (*m_BiosList)[(int)m_ComboBox.GetClientData(sel)];
|
||||
}
|
||||
|
||||
void Panels::BiosSelectorPanel::OnSettingsChanged()
|
||||
void Panels::BiosSelectorPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace Panels
|
|||
UsermodeSelectionPanel( wxWindow* parent, bool isFirstTime = true );
|
||||
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -90,7 +90,7 @@ namespace Panels
|
|||
LanguageSelectionPanel( wxWindow* parent );
|
||||
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -104,7 +104,7 @@ namespace Panels
|
|||
public:
|
||||
CpuPanelEE( wxWindow* parent );
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
class CpuPanelVU : public BaseApplicableConfigPanel
|
||||
|
@ -116,7 +116,7 @@ namespace Panels
|
|||
public:
|
||||
CpuPanelVU( wxWindow* parent );
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
class BaseAdvancedCpuOptions : public BaseApplicableConfigPanel
|
||||
|
@ -146,7 +146,7 @@ namespace Panels
|
|||
AdvancedOptionsFPU( wxWindow* parent );
|
||||
virtual ~AdvancedOptionsFPU() throw() { }
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
class AdvancedOptionsVU : public BaseAdvancedCpuOptions
|
||||
|
@ -155,7 +155,7 @@ namespace Panels
|
|||
AdvancedOptionsVU( wxWindow* parent );
|
||||
virtual ~AdvancedOptionsVU() throw() { }
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -176,7 +176,7 @@ namespace Panels
|
|||
virtual ~FrameSkipPanel() throw() {}
|
||||
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -202,7 +202,7 @@ namespace Panels
|
|||
virtual ~FramelimiterPanel() throw() {}
|
||||
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -227,7 +227,7 @@ namespace Panels
|
|||
GSWindowSettingsPanel( wxWindow* parent );
|
||||
virtual ~GSWindowSettingsPanel() throw() {}
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
class VideoPanel : public BaseApplicableConfigPanel
|
||||
|
@ -242,7 +242,7 @@ namespace Panels
|
|||
VideoPanel( wxWindow* parent );
|
||||
virtual ~VideoPanel() throw() {}
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
|
||||
protected:
|
||||
void OnOpenWindowSettings( wxCommandEvent& evt );
|
||||
|
@ -273,8 +273,8 @@ namespace Panels
|
|||
SpeedHacksPanel( wxWindow* parent );
|
||||
void Apply();
|
||||
void EnableStuff();
|
||||
void OnSettingsChanged();
|
||||
void OnSettingsChanged( const Pcsx2Config::SpeedhackOptions& opt );
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
void AppStatusEvent_OnSettingsApplied( const Pcsx2Config::SpeedhackOptions& opt );
|
||||
|
||||
protected:
|
||||
const wxChar* GetEEcycleSliderMsg( int val );
|
||||
|
@ -299,7 +299,7 @@ namespace Panels
|
|||
public:
|
||||
GameFixesPanel( wxWindow* parent );
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -319,7 +319,7 @@ namespace Panels
|
|||
virtual ~DirPickerPanel() throw() { }
|
||||
|
||||
void Apply();
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
|
||||
void Reset();
|
||||
wxDirName GetPath() const;
|
||||
|
@ -394,7 +394,7 @@ namespace Panels
|
|||
|
||||
protected:
|
||||
virtual void Apply();
|
||||
virtual void OnSettingsChanged();
|
||||
virtual void AppStatusEvent_OnSettingsApplied();
|
||||
virtual void DoRefresh();
|
||||
virtual bool ValidateEnumerationStatus();
|
||||
};
|
||||
|
@ -402,7 +402,8 @@ namespace Panels
|
|||
// --------------------------------------------------------------------------------------
|
||||
// PluginSelectorPanel
|
||||
// --------------------------------------------------------------------------------------
|
||||
class PluginSelectorPanel: public BaseSelectorPanel
|
||||
class PluginSelectorPanel: public BaseSelectorPanel,
|
||||
public IEventListener_Plugins
|
||||
{
|
||||
protected:
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -490,8 +491,6 @@ namespace Panels
|
|||
ScopedPtr<wxArrayString> m_FileList; // list of potential plugin files
|
||||
ScopedPtr<EnumThread> m_EnumeratorThread;
|
||||
|
||||
EventListenerBinding<PluginEventType> m_Listener_CorePluginStatus;
|
||||
|
||||
public:
|
||||
virtual ~PluginSelectorPanel() throw();
|
||||
PluginSelectorPanel( wxWindow* parent, int idealWidth=wxDefaultCoord );
|
||||
|
@ -500,7 +499,7 @@ namespace Panels
|
|||
void Apply();
|
||||
|
||||
protected:
|
||||
static void __evt_fastcall OnCorePluginStatusChanged( void* obj, PluginEventType& evt );
|
||||
void DispatchEvent( const PluginEventType& evt );
|
||||
|
||||
void OnConfigure_Clicked( wxCommandEvent& evt );
|
||||
void OnShowStatusBar( wxCommandEvent& evt );
|
||||
|
@ -509,7 +508,7 @@ namespace Panels
|
|||
virtual void OnProgress( wxCommandEvent& evt );
|
||||
virtual void OnEnumComplete( wxCommandEvent& evt );
|
||||
|
||||
virtual void OnSettingsChanged();
|
||||
virtual void AppStatusEvent_OnSettingsApplied();
|
||||
|
||||
virtual void DoRefresh();
|
||||
virtual bool ValidateEnumerationStatus();
|
||||
|
|
|
@ -106,7 +106,7 @@ Panels::AdvancedOptionsFPU::AdvancedOptionsFPU( wxWindow* parent )
|
|||
m_RoundModePanel->Realize();
|
||||
m_ClampModePanel->Realize();
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,7 +121,7 @@ Panels::AdvancedOptionsVU::AdvancedOptionsVU( wxWindow* parent )
|
|||
m_RoundModePanel->Realize();
|
||||
m_ClampModePanel->Realize();
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
Panels::CpuPanelEE::CpuPanelEE( wxWindow* parent )
|
||||
|
@ -175,7 +175,7 @@ Panels::CpuPanelEE::CpuPanelEE( wxWindow* parent )
|
|||
*this += new wxStaticLine( this ) | wxSF.Border(wxALL, 18).Expand();
|
||||
*this += new AdvancedOptionsFPU( this ) | StdExpand();
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
Panels::CpuPanelVU::CpuPanelVU( wxWindow* parent )
|
||||
|
@ -221,7 +221,7 @@ Panels::CpuPanelVU::CpuPanelVU( wxWindow* parent )
|
|||
*this += new wxStaticLine( this ) | wxSF.Border(wxALL, 18).Expand();
|
||||
*this += new AdvancedOptionsVU( this ) | StdExpand();
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::CpuPanelEE::Apply()
|
||||
|
@ -231,7 +231,7 @@ void Panels::CpuPanelEE::Apply()
|
|||
recOps.EnableIOP = !!m_panel_RecIOP->GetSelection();
|
||||
}
|
||||
|
||||
void Panels::CpuPanelEE::OnSettingsChanged()
|
||||
void Panels::CpuPanelEE::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_panel_RecEE->Enable( x86caps.hasStreamingSIMD2Extensions );
|
||||
|
||||
|
@ -253,7 +253,7 @@ void Panels::CpuPanelVU::Apply()
|
|||
recOps.UseMicroVU1 = m_panel_VU1->GetSelection() == 1;
|
||||
}
|
||||
|
||||
void Panels::CpuPanelVU::OnSettingsChanged()
|
||||
void Panels::CpuPanelVU::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_panel_VU0->Enable( x86caps.hasStreamingSIMD2Extensions );
|
||||
m_panel_VU1->Enable( x86caps.hasStreamingSIMD2Extensions );
|
||||
|
@ -300,7 +300,7 @@ void Panels::AdvancedOptionsFPU::Apply()
|
|||
cpuOps.ApplySanityCheck();
|
||||
}
|
||||
|
||||
void Panels::AdvancedOptionsFPU::OnSettingsChanged()
|
||||
void Panels::AdvancedOptionsFPU::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
const Pcsx2Config::CpuOptions& cpuOps( g_Conf->EmuOptions.Cpu );
|
||||
const Pcsx2Config::RecompilerOptions& recOps( cpuOps.Recompiler );
|
||||
|
@ -333,7 +333,7 @@ void Panels::AdvancedOptionsVU::Apply()
|
|||
cpuOps.ApplySanityCheck();
|
||||
}
|
||||
|
||||
void Panels::AdvancedOptionsVU::OnSettingsChanged()
|
||||
void Panels::AdvancedOptionsVU::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
const Pcsx2Config::CpuOptions& cpuOps( g_Conf->EmuOptions.Cpu );
|
||||
const Pcsx2Config::RecompilerOptions& recOps( cpuOps.Recompiler );
|
||||
|
|
|
@ -110,7 +110,7 @@ Panels::DirPickerPanel::DirPickerPanel( wxWindow* parent, FoldersEnum_t folderid
|
|||
// wx warns when paths don't exist, but this is typically normal when the wizard
|
||||
// creates its child controls. So let's ignore them.
|
||||
wxDoNotLogInThisScope please;
|
||||
OnSettingsChanged(); // forces default settings based on g_Conf
|
||||
AppStatusEvent_OnSettingsApplied(); // forces default settings based on g_Conf
|
||||
}
|
||||
|
||||
Panels::DirPickerPanel& Panels::DirPickerPanel::SetStaticDesc( const wxString& msg )
|
||||
|
@ -133,7 +133,7 @@ void Panels::DirPickerPanel::Reset()
|
|||
m_pickerCtrl->SetPath( GetNormalizedConfigFolder( m_FolderId ) );
|
||||
}
|
||||
|
||||
void Panels::DirPickerPanel::OnSettingsChanged()
|
||||
void Panels::DirPickerPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
|
|
@ -105,10 +105,10 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent )
|
|||
*centerSizer += GetSizer() | pxCenter;
|
||||
SetSizer( centerSizer, false );
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::GSWindowSettingsPanel::OnSettingsChanged()
|
||||
void Panels::GSWindowSettingsPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
const AppConfig::GSWindowOptions& conf( g_Conf->GSWindow );
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) :
|
|||
L"will need to turn off fixes manually when changing games."
|
||||
));
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
// I could still probably get rid of the for loop, but I think this is clearer.
|
||||
|
@ -92,7 +92,7 @@ void Panels::GameFixesPanel::Apply()
|
|||
}
|
||||
}
|
||||
|
||||
void Panels::GameFixesPanel::OnSettingsChanged()
|
||||
void Panels::GameFixesPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
const Pcsx2Config::GamefixOptions& opts( g_Conf->EmuOptions.Gamefixes );
|
||||
for( int i=0; i<NUM_OF_GAME_FIXES; ++i )
|
||||
|
|
|
@ -227,10 +227,10 @@ Panels::LogOptionsPanel::LogOptionsPanel(wxWindow* parent )
|
|||
|
||||
Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(LogOptionsPanel::OnCheckBoxClicked) );
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::LogOptionsPanel::OnSettingsChanged()
|
||||
void Panels::LogOptionsPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
TraceLogFilters& conf( g_Conf->EmuOptions.Trace );
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace Panels
|
|||
LogOptionsPanel( wxWindow* parent );
|
||||
virtual ~LogOptionsPanel() throw() {}
|
||||
|
||||
void OnSettingsChanged();
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
void OnUpdateEnableAll();
|
||||
void OnCheckBoxClicked(wxCommandEvent &event);
|
||||
void Apply();
|
||||
|
|
|
@ -152,14 +152,14 @@ BaseApplicableConfigPanel::~BaseApplicableConfigPanel() throw()
|
|||
|
||||
BaseApplicableConfigPanel::BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient )
|
||||
: wxPanelWithHelpers( parent, orient )
|
||||
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int>( this, OnSettingsApplied ) )
|
||||
, m_AppStatusHelper( this )
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
BaseApplicableConfigPanel::BaseApplicableConfigPanel( wxWindow* parent, wxOrientation orient, const wxString& staticLabel )
|
||||
: wxPanelWithHelpers( parent, orient, staticLabel )
|
||||
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int>( this, OnSettingsApplied ) )
|
||||
, m_AppStatusHelper( this )
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
@ -181,12 +181,7 @@ void BaseApplicableConfigPanel::Init()
|
|||
}
|
||||
}
|
||||
|
||||
void __evt_fastcall BaseApplicableConfigPanel::OnSettingsApplied( void* obj, int& ini )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
((BaseApplicableConfigPanel*)obj)->OnSettingsChanged();
|
||||
}
|
||||
|
||||
void BaseApplicableConfigPanel::AppStatusEvent_OnSettingsApplied() {}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
Panels::UsermodeSelectionPanel::UsermodeSelectionPanel( wxWindow* parent, bool isFirstTime )
|
||||
|
@ -226,7 +221,7 @@ Panels::UsermodeSelectionPanel::UsermodeSelectionPanel( wxWindow* parent, bool i
|
|||
*this += m_radio_UserMode | pxSizerFlags::StdExpand();
|
||||
*this += 4;
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::UsermodeSelectionPanel::Apply()
|
||||
|
@ -234,7 +229,7 @@ void Panels::UsermodeSelectionPanel::Apply()
|
|||
UseAdminMode = (m_radio_UserMode->GetSelection() == 1);
|
||||
}
|
||||
|
||||
void Panels::UsermodeSelectionPanel::OnSettingsChanged()
|
||||
void Panels::UsermodeSelectionPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_radio_UserMode->SetSelection( (int)UseAdminMode );
|
||||
}
|
||||
|
@ -267,7 +262,7 @@ Panels::LanguageSelectionPanel::LanguageSelectionPanel( wxWindow* parent )
|
|||
*this += m_picker | pxSizerFlags::StdSpace();
|
||||
|
||||
m_picker->SetSelection( cursel );
|
||||
//OnSettingsChanged();
|
||||
//AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::LanguageSelectionPanel::Apply()
|
||||
|
@ -289,7 +284,7 @@ void Panels::LanguageSelectionPanel::Apply()
|
|||
}
|
||||
}
|
||||
|
||||
void Panels::LanguageSelectionPanel::OnSettingsChanged()
|
||||
void Panels::LanguageSelectionPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_picker->SetSelection( g_Conf->LanguageId );
|
||||
}
|
||||
|
|
|
@ -230,24 +230,21 @@ void Panels::PluginSelectorPanel::ComboBoxPanel::Reset()
|
|||
// =====================================================================================================
|
||||
// PluginSelectorPanel
|
||||
// =====================================================================================================
|
||||
void __evt_fastcall Panels::PluginSelectorPanel::OnCorePluginStatusChanged( void* obj, PluginEventType& evt )
|
||||
void Panels::PluginSelectorPanel::DispatchEvent( const PluginEventType& evt )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
if( (evt != PluginsEvt_Loaded) && (evt != PluginsEvt_Unloaded) ) return; // everything else we don't care about
|
||||
|
||||
PluginSelectorPanel& panel = *(PluginSelectorPanel*)obj;
|
||||
|
||||
if( panel.IsBeingDeleted() ) return;
|
||||
if( IsBeingDeleted() ) return;
|
||||
|
||||
const PluginInfo* pi = tbl_PluginInfo; do
|
||||
{
|
||||
wxComboBox& box( panel.m_ComponentBoxes->Get(pi->id) );
|
||||
wxComboBox& box( m_ComponentBoxes->Get(pi->id) );
|
||||
int sel = box.GetSelection();
|
||||
if( sel == wxNOT_FOUND ) continue;
|
||||
|
||||
panel.m_ComponentBoxes->GetConfigButton(pi->id).Enable(
|
||||
(panel.m_FileList==NULL || panel.m_FileList->Count() == 0) ? false :
|
||||
g_Conf->FullpathMatchTest( pi->id,(*panel.m_FileList)[((int)box.GetClientData(sel))] )
|
||||
m_ComponentBoxes->GetConfigButton(pi->id).Enable(
|
||||
(m_FileList==NULL || m_FileList->Count() == 0) ? false :
|
||||
g_Conf->FullpathMatchTest( pi->id,(*m_FileList)[((int)box.GetClientData(sel))] )
|
||||
);
|
||||
} while( ++pi, pi->shortname != NULL );
|
||||
|
||||
|
@ -255,7 +252,6 @@ void __evt_fastcall Panels::PluginSelectorPanel::OnCorePluginStatusChanged( void
|
|||
|
||||
Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow* parent, int idealWidth )
|
||||
: BaseSelectorPanel( parent )
|
||||
, m_Listener_CorePluginStatus( wxGetApp().Source_CorePluginStatus(), EventListener<PluginEventType> ( this, OnCorePluginStatusChanged ) )
|
||||
{
|
||||
if( idealWidth != wxDefaultCoord ) m_idealWidth = idealWidth;
|
||||
|
||||
|
@ -282,7 +278,7 @@ Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow* parent, int idealWid
|
|||
|
||||
Connect( ButtonId_Configure, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PluginSelectorPanel::OnConfigure_Clicked ) );
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
Panels::PluginSelectorPanel::~PluginSelectorPanel() throw()
|
||||
|
@ -290,7 +286,7 @@ Panels::PluginSelectorPanel::~PluginSelectorPanel() throw()
|
|||
CancelRefresh(); // in case the enumeration thread is currently refreshing...
|
||||
}
|
||||
|
||||
void Panels::PluginSelectorPanel::OnSettingsChanged()
|
||||
void Panels::PluginSelectorPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_ComponentBoxes->GetDirPicker().Reset();
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent )
|
|||
Connect( m_check_Enable->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( SpeedHacksPanel::OnEnable_Toggled ) );
|
||||
Connect( wxID_DEFAULT, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SpeedHacksPanel::Defaults_Click ) );
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::SpeedHacksPanel::EnableStuff()
|
||||
|
@ -282,12 +282,12 @@ void Panels::SpeedHacksPanel::EnableStuff()
|
|||
}
|
||||
}
|
||||
|
||||
void Panels::SpeedHacksPanel::OnSettingsChanged()
|
||||
void Panels::SpeedHacksPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
OnSettingsChanged( g_Conf->EmuOptions.Speedhacks );
|
||||
AppStatusEvent_OnSettingsApplied( g_Conf->EmuOptions.Speedhacks );
|
||||
}
|
||||
|
||||
void Panels::SpeedHacksPanel::OnSettingsChanged( const Pcsx2Config::SpeedhackOptions& opts )
|
||||
void Panels::SpeedHacksPanel::AppStatusEvent_OnSettingsApplied( const Pcsx2Config::SpeedhackOptions& opts )
|
||||
{
|
||||
const bool enabled = g_Conf->EnableSpeedHacks;
|
||||
|
||||
|
@ -335,7 +335,7 @@ void Panels::SpeedHacksPanel::OnEnable_Toggled( wxCommandEvent& evt )
|
|||
|
||||
void Panels::SpeedHacksPanel::Defaults_Click( wxCommandEvent& evt )
|
||||
{
|
||||
OnSettingsChanged( Pcsx2Config::SpeedhackOptions() );
|
||||
AppStatusEvent_OnSettingsApplied( Pcsx2Config::SpeedhackOptions() );
|
||||
evt.Skip();
|
||||
}
|
||||
|
||||
|
|
|
@ -105,10 +105,10 @@ Panels::FramelimiterPanel::FramelimiterPanel( wxWindow* parent )
|
|||
L"percentages of the default region-based framerate, which can also be configured below." )
|
||||
);
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::FramelimiterPanel::OnSettingsChanged()
|
||||
void Panels::FramelimiterPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
const AppConfig::GSWindowOptions& appwin( g_Conf->GSWindow );
|
||||
const AppConfig::FramerateOptions& appfps( g_Conf->Framerate );
|
||||
|
@ -226,10 +226,10 @@ Panels::FrameSkipPanel::FrameSkipPanel( wxWindow* parent )
|
|||
L"Enabling it will cause severe graphical errors in some games, and so it should be considered a speedhack." )
|
||||
);
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::FrameSkipPanel::OnSettingsChanged()
|
||||
void Panels::FrameSkipPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
const AppConfig::FramerateOptions& appfps( g_Conf->Framerate );
|
||||
const Pcsx2Config::GSOptions& gsconf( g_Conf->EmuOptions.GS );
|
||||
|
@ -332,7 +332,7 @@ Panels::VideoPanel::VideoPanel( wxWindow* parent ) :
|
|||
|
||||
Connect( m_button_OpenWindowSettings->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(VideoPanel::OnOpenWindowSettings) );
|
||||
|
||||
OnSettingsChanged();
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::VideoPanel::OnOpenWindowSettings( wxCommandEvent& evt )
|
||||
|
@ -348,7 +348,7 @@ void Panels::VideoPanel::Apply()
|
|||
g_Conf->EmuOptions.GS.DisableOutput = m_check_DisableOutput->GetValue();
|
||||
}
|
||||
|
||||
void Panels::VideoPanel::OnSettingsChanged()
|
||||
void Panels::VideoPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_check_SynchronousGS->SetValue( g_Conf->EmuOptions.GS.SynchronousMTGS );
|
||||
m_check_DisableOutput->SetValue( g_Conf->EmuOptions.GS.DisableOutput );
|
||||
|
|
|
@ -29,6 +29,10 @@ using namespace Threading;
|
|||
|
||||
static FnType_OnThreadComplete* Callback_PluginsLoadComplete = NULL;
|
||||
|
||||
// The GS plugin needs to be opened to save/load the state during plugin configuration, but
|
||||
// the window shouldn't. This blocks it. :)
|
||||
static bool s_DisableGsWindow = false;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppPluginManager
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -89,7 +93,7 @@ public:
|
|||
// Yay, this plugin is guaranteed to always be opened first and closed last.
|
||||
bool OpenPlugin_GS()
|
||||
{
|
||||
if( GSopen2 != NULL )
|
||||
if( GSopen2 != NULL && !s_DisableGsWindow )
|
||||
{
|
||||
sApp.OpenGsPanel();
|
||||
}
|
||||
|
@ -187,6 +191,8 @@ void LoadPluginsTask::OnCleanupInThread()
|
|||
SaveSinglePluginHelper::SaveSinglePluginHelper( PluginsEnum_t pid )
|
||||
: m_plugstore( L"PluginConf Savestate" )
|
||||
{
|
||||
s_DisableGsWindow = true;
|
||||
|
||||
m_whereitsat = NULL;
|
||||
m_resume = false;
|
||||
m_pid = pid;
|
||||
|
@ -210,14 +216,24 @@ SaveSinglePluginHelper::SaveSinglePluginHelper( PluginsEnum_t pid )
|
|||
|
||||
SaveSinglePluginHelper::~SaveSinglePluginHelper() throw()
|
||||
{
|
||||
if( m_validstate )
|
||||
try
|
||||
{
|
||||
Console.WriteLn( Color_Green, L"Recovering single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
||||
memLoadingState load( *m_whereitsat );
|
||||
if( m_plugstore.IsDisposed() ) load.SeekToSection( m_pid );
|
||||
g_plugins->Freeze( m_pid, load );
|
||||
if( m_validstate )
|
||||
{
|
||||
Console.WriteLn( Color_Green, L"Recovering single plugin: " + tbl_PluginInfo[m_pid].GetShortname() );
|
||||
memLoadingState load( *m_whereitsat );
|
||||
if( m_plugstore.IsDisposed() ) load.SeekToSection( m_pid );
|
||||
g_plugins->Freeze( m_pid, load );
|
||||
g_plugins->Close( m_pid );
|
||||
}
|
||||
}
|
||||
catch( Exception::BaseException& ex )
|
||||
{
|
||||
s_DisableGsWindow = false;
|
||||
throw;
|
||||
}
|
||||
|
||||
s_DisableGsWindow = false;
|
||||
if( m_resume ) CoreThread.Resume();
|
||||
}
|
||||
|
||||
|
@ -256,15 +272,14 @@ void ConvertPluginFilenames( wxString (&passins)[PluginId_Count] )
|
|||
}
|
||||
|
||||
// boolean lock modified from the main thread only...
|
||||
static bool plugin_load_lock = false;
|
||||
static LoadPluginsTask* plugin_load_lock = NULL;
|
||||
|
||||
void Pcsx2App::ReloadPlugins()
|
||||
{
|
||||
if( SelfMethodInvoke( &Pcsx2App::ReloadPlugins ) ) return;
|
||||
if( InvokeMethodOnMainThread( &Pcsx2App::ReloadPlugins ) ) return;
|
||||
|
||||
if( plugin_load_lock ) return;
|
||||
CoreThread.Cancel();
|
||||
m_CorePlugins = NULL;
|
||||
UnloadPlugins();
|
||||
|
||||
wxString passins[PluginId_Count];
|
||||
|
||||
|
@ -276,27 +291,29 @@ void Pcsx2App::ReloadPlugins()
|
|||
passins[pi->id] = g_Conf->FullpathTo( pi->id );
|
||||
} while( ++pi, pi->shortname != NULL );
|
||||
|
||||
(new LoadPluginsTask( passins ))->Start();
|
||||
// ... and when it finishes it posts up a OnLoadPluginsComplete(). Bye. :)
|
||||
plugin_load_lock = new LoadPluginsTask(passins);
|
||||
plugin_load_lock->Start();
|
||||
|
||||
plugin_load_lock = true;
|
||||
// ... and when it finishes it posts up a OnLoadPluginsComplete(). Bye. :)
|
||||
}
|
||||
|
||||
// Note: If the ClientData paremeter of wxCommandEvt is NULL, this message simply dispatches
|
||||
// Note: If the ClientData parameter of wxCommandEvt is NULL, this message simply dispatches
|
||||
// the plugged in listeners.
|
||||
void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt )
|
||||
{
|
||||
plugin_load_lock = false;
|
||||
|
||||
FnType_OnThreadComplete* fn_tmp = Callback_PluginsLoadComplete;
|
||||
|
||||
if( evt.GetClientData() != NULL )
|
||||
if( LoadPluginsTask* pluginthread = (LoadPluginsTask*)evt.GetClientData() )
|
||||
{
|
||||
// scoped ptr ensures the thread object is cleaned up even on exception:
|
||||
ScopedPtr<LoadPluginsTask> killTask( pluginthread );
|
||||
|
||||
pxAssume( plugin_load_lock == pluginthread );
|
||||
plugin_load_lock = NULL;
|
||||
|
||||
if( !pxAssertDev( !m_CorePlugins, "LoadPlugins thread just finished, but CorePlugins state != NULL (odd!)." ) )
|
||||
m_CorePlugins = NULL;
|
||||
|
||||
// scoped ptr ensures the thread object is cleaned up even on exception:
|
||||
ScopedPtr<LoadPluginsTask> killTask( (LoadPluginsTask*)evt.GetClientData() );
|
||||
killTask->RethrowException();
|
||||
m_CorePlugins = killTask->Result;
|
||||
}
|
||||
|
@ -306,6 +323,12 @@ void Pcsx2App::OnLoadPluginsComplete( wxCommandEvent& evt )
|
|||
PostPluginStatus( PluginsEvt_Loaded );
|
||||
}
|
||||
|
||||
void Pcsx2App::CancelLoadingPlugins()
|
||||
{
|
||||
if( plugin_load_lock )
|
||||
plugin_load_lock->Cancel();
|
||||
}
|
||||
|
||||
void Pcsx2App::PostPluginStatus( PluginEventType pevt )
|
||||
{
|
||||
if( !wxThread::IsMain() )
|
||||
|
@ -314,7 +337,7 @@ void Pcsx2App::PostPluginStatus( PluginEventType pevt )
|
|||
}
|
||||
else
|
||||
{
|
||||
sApp.Source_CorePluginStatus().Dispatch( pevt );
|
||||
sApp.DispatchEvent( pevt );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "MainFrame.h"
|
||||
|
||||
#include "IniInterface.h"
|
||||
|
||||
// FIXME : This needs to handle removed/missing ISOs somehow, although I'm not sure the
|
||||
// best approach. I think I'd prefer for missing entries to only be removed when they
|
||||
|
@ -27,8 +27,6 @@
|
|||
RecentIsoManager::RecentIsoManager( wxMenu* menu )
|
||||
: m_Menu( menu )
|
||||
, 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 ) )
|
||||
{
|
||||
m_cursel = 0;
|
||||
m_Separator = NULL;
|
||||
|
@ -139,13 +137,15 @@ void RecentIsoManager::InsertIntoMenu( int id )
|
|||
curitem.ItemPtr->Check();
|
||||
}
|
||||
|
||||
void RecentIsoManager::DoSettingsApplied( int& ini )
|
||||
void RecentIsoManager::AppEvent_OnSettingsApplied()
|
||||
{
|
||||
// TODO : Implement application of Recent Iso List "maximum" history option
|
||||
}
|
||||
|
||||
void RecentIsoManager::DoSettingsLoadSave( IniInterface& ini )
|
||||
void RecentIsoManager::AppEvent_OnSettingsLoadSave( const AppSettingsEventInfo& evt )
|
||||
{
|
||||
IniInterface& ini( evt.GetIni() );
|
||||
|
||||
ini.GetConfig().SetRecordDefaults( false );
|
||||
|
||||
if( ini.IsSaving() )
|
||||
|
@ -179,15 +179,3 @@ void RecentIsoManager::DoSettingsLoadSave( IniInterface& ini )
|
|||
|
||||
ini.GetConfig().SetRecordDefaults( true );
|
||||
}
|
||||
|
||||
void __evt_fastcall RecentIsoManager::OnSettingsLoadSave( void* obj, IniInterface& ini )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
((RecentIsoManager*)obj)->DoSettingsLoadSave( ini );
|
||||
}
|
||||
|
||||
void __evt_fastcall RecentIsoManager::OnSettingsApplied( void* obj, int& ini )
|
||||
{
|
||||
if( obj == NULL ) return;
|
||||
((RecentIsoManager*)obj)->DoSettingsApplied( ini );
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
// RecentIsoManager
|
||||
// --------------------------------------------------------------------------------------
|
||||
class RecentIsoManager : public wxEvtHandler
|
||||
class RecentIsoManager : public wxEvtHandler,
|
||||
public IEventListener_AppStatus
|
||||
{
|
||||
protected:
|
||||
struct RecentItem
|
||||
|
@ -43,9 +44,6 @@ protected:
|
|||
|
||||
wxMenuItem* m_Separator;
|
||||
|
||||
EventListenerBinding<IniInterface> m_Listener_SettingsLoadSave;
|
||||
EventListenerBinding<int> m_Listener_SettingsApplied;
|
||||
|
||||
public:
|
||||
RecentIsoManager( wxMenu* menu );
|
||||
virtual ~RecentIsoManager() throw();
|
||||
|
@ -56,11 +54,9 @@ public:
|
|||
|
||||
protected:
|
||||
void InsertIntoMenu( int id );
|
||||
void DoSettingsLoadSave( IniInterface& ini );
|
||||
void DoSettingsApplied( int& val );
|
||||
void OnChangedSelection( wxCommandEvent& evt );
|
||||
|
||||
static void __evt_fastcall OnSettingsLoadSave( void* obj, IniInterface& evt );
|
||||
static void __evt_fastcall OnSettingsApplied( void* obj, int& evt );
|
||||
void AppEvent_OnSettingsLoadSave( const AppSettingsEventInfo& ini );
|
||||
void AppEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
|
|
|
@ -21,29 +21,20 @@
|
|||
# include <wx/msw/wrapwin.h> // needed for windows-specific rich text messages to make scrolling not lame
|
||||
#endif
|
||||
|
||||
void __evt_fastcall pxLogTextCtrl::OnCoreThreadStatusChanged( void* obj, wxCommandEvent& evt )
|
||||
void pxLogTextCtrl::DispatchEvent( const CoreThreadStatus& status )
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
if( obj == NULL ) return;
|
||||
pxLogTextCtrl* mframe = (pxLogTextCtrl*)obj;
|
||||
|
||||
// See ConcludeIssue for details on WM_VSCROLL
|
||||
|
||||
if( mframe->HasWriteLock() ) return;
|
||||
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||
if( HasWriteLock() ) return;
|
||||
::SendMessage((HWND)GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __evt_fastcall pxLogTextCtrl::OnCorePluginStatusChanged( void* obj, PluginEventType& evt )
|
||||
void pxLogTextCtrl::DispatchEvent( const PluginEventType& evt )
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
if( obj == NULL ) return;
|
||||
pxLogTextCtrl* mframe = (pxLogTextCtrl*)obj;
|
||||
|
||||
// See ConcludeIssue for details on WM_VSCROLL
|
||||
|
||||
if( mframe->HasWriteLock() ) return;
|
||||
::SendMessage((HWND)mframe->GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||
if( HasWriteLock() ) return;
|
||||
::SendMessage((HWND)GetHWND(), WM_VSCROLL, SB_BOTTOM, (LPARAM)NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -51,9 +42,6 @@ pxLogTextCtrl::pxLogTextCtrl( wxWindow* parent )
|
|||
: wxTextCtrl( parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2
|
||||
)
|
||||
|
||||
, m_Listener_CoreThreadStatus ( wxGetApp().Source_CoreThreadStatus(), CmdEvt_Listener ( this, OnCoreThreadStatusChanged ) )
|
||||
, m_Listener_CorePluginStatus ( wxGetApp().Source_CorePluginStatus(), EventListener<PluginEventType> ( this, OnCorePluginStatusChanged ) )
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
m_win32_LinesPerScroll = 10;
|
||||
|
|
|
@ -1820,6 +1820,10 @@
|
|||
RelativePath="..\..\gui\AppCoreThread.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\AppEventSources.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\AppInit.cpp"
|
||||
>
|
||||
|
@ -1896,10 +1900,6 @@
|
|||
RelativePath="..\..\gui\Saveslots.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\wxAppWithHelpers.cpp"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="Dialogs"
|
||||
>
|
||||
|
@ -1967,6 +1967,10 @@
|
|||
RelativePath="..\..\gui\Dialogs\PickUserModeDialog.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Dialogs\StuckThreadDialog.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Dialogs\SysConfigDialog.cpp"
|
||||
>
|
||||
|
@ -2535,6 +2539,14 @@
|
|||
RelativePath="..\..\gui\AppConfig.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\AppEventListeners.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\AppForwardDefs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\ApplyState.h"
|
||||
>
|
||||
|
@ -2567,10 +2579,6 @@
|
|||
RelativePath="..\..\gui\RecentIsoList.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\wxAppWithHelpers.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Win32"
|
||||
|
|
|
@ -25,13 +25,8 @@ int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
|||
if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION )
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
PageFaultInfo info( (uptr)eps->ExceptionRecord->ExceptionInformation[1] );
|
||||
|
||||
Source_PageFault.DispatchException( info );
|
||||
|
||||
if( info.handled ) return EXCEPTION_CONTINUE_EXECUTION;
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
Source_PageFault.Dispatch( PageFaultInfo( (uptr)eps->ExceptionRecord->ExceptionInformation[1] ) );
|
||||
return Source_PageFault.WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void InstallSignalHandler()
|
||||
|
|
|
@ -729,8 +729,8 @@ Global
|
|||
{6BC4D85D-A399-407E-96A9-CD5416A54269}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{6BC4D85D-A399-407E-96A9-CD5416A54269}.Release|Win32.Build.0 = Release|Win32
|
||||
{6BC4D85D-A399-407E-96A9-CD5416A54269}.Release|x64.ActiveCfg = Release|Win32
|
||||
{0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.ActiveCfg = Debug (NO ASIO)|Win32
|
||||
{0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|Win32.Build.0 = Debug (NO ASIO)|Win32
|
||||
{0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0A18A071-125E-442F-AFF7-A3F68ABECF99}.Debug|x64.Build.0 = Debug|x64
|
||||
{0A18A071-125E-442F-AFF7-A3F68ABECF99}.Devel|Win32.ActiveCfg = Release (NO ASIO)|Win32
|
||||
|
|
|
@ -257,20 +257,20 @@ public:
|
|||
CfgReadStr( L"PORTAUDIO", L"Device", m_Device, 254, L"default" );
|
||||
|
||||
m_ApiId = -1;
|
||||
if(api == L"InDevelopment") m_ApiId = paInDevelopment; /* use while developing support for a new host API */
|
||||
if(api == L"DirectSound") m_ApiId = paDirectSound;
|
||||
if(api == L"MME") m_ApiId = paMME;
|
||||
if(api == L"ASIO") m_ApiId = paASIO;
|
||||
if(api == L"SoundManager") m_ApiId = paSoundManager;
|
||||
if(api == L"CoreAudio") m_ApiId = paCoreAudio;
|
||||
if(api == L"OSS") m_ApiId = paOSS;
|
||||
if(api == L"ALSA") m_ApiId = paALSA;
|
||||
if(api == L"AL") m_ApiId = paAL;
|
||||
if(api == L"BeOS") m_ApiId = paBeOS;
|
||||
if(api == L"WDMKS") m_ApiId = paWDMKS;
|
||||
if(api == L"JACK") m_ApiId = paJACK;
|
||||
if(api == L"WASAPI") m_ApiId = paWASAPI;
|
||||
if(api == L"AudioScienceHPI") m_ApiId = paAudioScienceHPI;
|
||||
if(api == L"InDevelopment") m_ApiId = paInDevelopment; /* use while developing support for a new host API */
|
||||
if(api == L"DirectSound") m_ApiId = paDirectSound;
|
||||
if(api == L"MME") m_ApiId = paMME;
|
||||
if(api == L"ASIO") m_ApiId = paASIO;
|
||||
if(api == L"SoundManager") m_ApiId = paSoundManager;
|
||||
if(api == L"CoreAudio") m_ApiId = paCoreAudio;
|
||||
if(api == L"OSS") m_ApiId = paOSS;
|
||||
if(api == L"ALSA") m_ApiId = paALSA;
|
||||
if(api == L"AL") m_ApiId = paAL;
|
||||
if(api == L"BeOS") m_ApiId = paBeOS;
|
||||
if(api == L"WDMKS") m_ApiId = paWDMKS;
|
||||
if(api == L"JACK") m_ApiId = paJACK;
|
||||
if(api == L"WASAPI") m_ApiId = paWASAPI;
|
||||
if(api == L"AudioScienceHPI") m_ApiId = paAudioScienceHPI;
|
||||
|
||||
}
|
||||
|
||||
|
@ -279,21 +279,21 @@ public:
|
|||
wstring api;
|
||||
switch(m_ApiId)
|
||||
{
|
||||
case paInDevelopment: api = L"InDevelopment"; break; /* use while developing support for a new host API */
|
||||
case paDirectSound: api = L"DirectSound"; break;
|
||||
case paMME: api = L"MME"; break;
|
||||
case paASIO: api = L"ASIO"; break;
|
||||
case paSoundManager: api = L"SoundManager"; break;
|
||||
case paCoreAudio: api = L"CoreAudio"; break;
|
||||
case paOSS: api = L"OSS"; break;
|
||||
case paALSA: api = L"ALSA"; break;
|
||||
case paAL: api = L"AL"; break;
|
||||
case paBeOS: api = L"BeOS"; break;
|
||||
case paWDMKS: api = L"WDMKS"; break;
|
||||
case paJACK: api = L"JACK"; break;
|
||||
case paWASAPI: api = L"WASAPI"; break;
|
||||
case paAudioScienceHPI: api = L"AudioScienceHPI"; break;
|
||||
default: api = L"Unknown";
|
||||
case paInDevelopment: api = L"InDevelopment"; break; /* use while developing support for a new host API */
|
||||
case paDirectSound: api = L"DirectSound"; break;
|
||||
case paMME: api = L"MME"; break;
|
||||
case paASIO: api = L"ASIO"; break;
|
||||
case paSoundManager: api = L"SoundManager"; break;
|
||||
case paCoreAudio: api = L"CoreAudio"; break;
|
||||
case paOSS: api = L"OSS"; break;
|
||||
case paALSA: api = L"ALSA"; break;
|
||||
case paAL: api = L"AL"; break;
|
||||
case paBeOS: api = L"BeOS"; break;
|
||||
case paWDMKS: api = L"WDMKS"; break;
|
||||
case paJACK: api = L"JACK"; break;
|
||||
case paWASAPI: api = L"WASAPI"; break;
|
||||
case paAudioScienceHPI: api = L"AudioScienceHPI"; break;
|
||||
default: api = L"Unknown";
|
||||
}
|
||||
|
||||
CfgWriteStr( L"PORTAUDIO", L"HostApi", api);
|
||||
|
|
Loading…
Reference in New Issue