Added some hourglass cursors for various things; renamed more Semaphore and Mutex APIs (I'm too indecisive >_<)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2109 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-11-01 09:27:16 +00:00
parent 4e69680c81
commit 376a2c94b1
14 changed files with 197 additions and 60 deletions

View File

@ -170,8 +170,8 @@ namespace Threading
void Post(); void Post();
void Post( int multiple ); void Post( int multiple );
void WaitRaw(); void WaitWithoutYield();
bool WaitRaw( const wxTimeSpan& timeout ); bool WaitWithoutYield( const wxTimeSpan& timeout );
void WaitNoCancel(); void WaitNoCancel();
void WaitNoCancel( const wxTimeSpan& timeout ); void WaitNoCancel( const wxTimeSpan& timeout );
int Count(); int Count();
@ -199,8 +199,8 @@ namespace Threading
bool TryAcquire(); bool TryAcquire();
void Release(); void Release();
void FullBlockingAcquire(); void AcquireWithoutYield();
bool FullBlockingAcquire( const wxTimeSpan& timeout ); bool AcquireWithoutYield( const wxTimeSpan& timeout );
void Wait(); void Wait();
bool Wait( const wxTimeSpan& timeout ); bool Wait( const wxTimeSpan& timeout );

View File

@ -15,7 +15,11 @@
#pragma once #pragma once
#if wxUSE_GUI
#include "Dependencies.h" #include "Dependencies.h"
#include "ScopedPtr.h"
#include <stack>
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxGuiTools.h // wxGuiTools.h
@ -122,6 +126,53 @@ protected:
} }
}; };
// --------------------------------------------------------------------------------------
// MoreStockCursors
// --------------------------------------------------------------------------------------
// Because (inexplicably) the ArrowWait cursor isn't in wxWidgets stock list.
//
class MoreStockCursors
{
protected:
ScopedPtr<wxCursor> m_arrowWait;
public:
MoreStockCursors() { }
virtual ~MoreStockCursors() throw() { }
const wxCursor& GetArrowWait();
};
enum BusyCursorType
{
Cursor_NotBusy,
Cursor_KindaBusy,
Cursor_ReallyBusy,
};
extern MoreStockCursors StockCursors;
// --------------------------------------------------------------------------------------
// ScopedBusyCursor
// --------------------------------------------------------------------------------------
// ... because wxWidgets wxBusyCursor doesn't really do proper nesting (doesn't let me
// override a partially-busy cursor with a really busy one)
class ScopedBusyCursor
{
protected:
static std::stack<BusyCursorType> m_cursorStack;
static BusyCursorType m_defBusyType;
public:
ScopedBusyCursor( BusyCursorType busytype );
virtual ~ScopedBusyCursor() throw();
static void SetDefault( BusyCursorType busytype );
static void SetManualBusyCursor( BusyCursorType busytype );
};
extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos ); extern bool pxIsValidWindowPosition( const wxWindow& window, const wxPoint& windowPos );
extern wxRect wxGetDisplayArea(); extern wxRect wxGetDisplayArea();
#endif

View File

@ -18,6 +18,7 @@
#include "Threading.h" #include "Threading.h"
#include "wxBaseTools.h" #include "wxBaseTools.h"
#include "wxGuiTools.h"
#include "ThreadingInternal.h" #include "ThreadingInternal.h"
namespace Threading namespace Threading
@ -112,12 +113,13 @@ bool Threading::Mutex::RecreateIfLocked()
// if used from the main GUI thread, since it typically results in an unresponsive program. // if used from the main GUI thread, since it typically results in an unresponsive program.
// Call this method directly only if you know the code in question will be run from threads // Call this method directly only if you know the code in question will be run from threads
// other than the main thread. // other than the main thread.
void Threading::Mutex::FullBlockingAcquire() void Threading::Mutex::AcquireWithoutYield()
{ {
pxAssertMsg( !wxThread::IsMain(), "Unyielding mutex acquire issued from the main/gui thread. Please use Acquire() instead." );
pthread_mutex_lock( &m_mutex ); pthread_mutex_lock( &m_mutex );
} }
bool Threading::Mutex::FullBlockingAcquire( const wxTimeSpan& timeout ) bool Threading::Mutex::AcquireWithoutYield( const wxTimeSpan& timeout )
{ {
wxDateTime megafail( wxDateTime::UNow() + timeout ); wxDateTime megafail( wxDateTime::UNow() + timeout );
const timespec fail = { megafail.GetTicks(), megafail.GetMillisecond() * 1000000 }; const timespec fail = { megafail.GetTicks(), megafail.GetMillisecond() * 1000000 };
@ -134,7 +136,7 @@ bool Threading::Mutex::TryAcquire()
return EBUSY != pthread_mutex_trylock( &m_mutex ); return EBUSY != pthread_mutex_trylock( &m_mutex );
} }
// This is a wxApp-safe rendition of FullBlockingAcquire, which makes sure to execute pending app events // This is a wxApp-safe rendition of AcquireWithoutYield, which makes sure to execute pending app events
// and messages *if* the lock is performed from the main GUI thread. // and messages *if* the lock is performed from the main GUI thread.
// //
// Exceptions: // Exceptions:
@ -145,20 +147,20 @@ void Threading::Mutex::Acquire()
#if wxUSE_GUI #if wxUSE_GUI
if( !wxThread::IsMain() || (wxTheApp == NULL) ) if( !wxThread::IsMain() || (wxTheApp == NULL) )
{ {
FullBlockingAcquire(); pthread_mutex_lock( &m_mutex );
} }
else if( _WaitGui_RecursionGuard( "Mutex::Acquire" ) ) else if( _WaitGui_RecursionGuard( "Mutex::Acquire" ) )
{ {
if( !FullBlockingAcquire(def_deadlock_timeout) ) if( !AcquireWithoutYield(def_deadlock_timeout) )
throw Exception::ThreadTimedOut(); throw Exception::ThreadTimedOut();
} }
else else
{ {
while( !FullBlockingAcquire(def_yieldgui_interval) ) while( !AcquireWithoutYield(def_yieldgui_interval) )
wxTheApp->Yield( true ); wxTheApp->Yield( true );
} }
#else #else
FullBlockingAcquire(); pthread_mutex_lock( &m_mutex );
#endif #endif
} }
@ -170,23 +172,26 @@ bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
#if wxUSE_GUI #if wxUSE_GUI
if( !wxThread::IsMain() || (wxTheApp == NULL) ) if( !wxThread::IsMain() || (wxTheApp == NULL) )
{ {
return FullBlockingAcquire(timeout); return AcquireWithoutYield(timeout);
} }
else if( _WaitGui_RecursionGuard( "Mutex::Acquire(timeout)" ) ) else if( _WaitGui_RecursionGuard( "Mutex::Acquire(timeout)" ) )
{ {
ScopedBusyCursor hourglass( Cursor_ReallyBusy );
if( timeout > def_deadlock_timeout ) if( timeout > def_deadlock_timeout )
{ {
if( FullBlockingAcquire(def_deadlock_timeout) ) return true; if( AcquireWithoutYield(def_deadlock_timeout) ) return true;
throw Exception::ThreadTimedOut(); throw Exception::ThreadTimedOut();
} }
return FullBlockingAcquire( timeout ); return AcquireWithoutYield( timeout );
} }
else else
{ {
ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown( (timeout) ); wxTimeSpan countdown( (timeout) );
do { do {
if( FullBlockingAcquire( def_yieldgui_interval ) ) break; if( AcquireWithoutYield( def_yieldgui_interval ) ) break;
wxTheApp->Yield(true); wxTheApp->Yield(true);
countdown -= def_yieldgui_interval; countdown -= def_yieldgui_interval;
} while( countdown.GetMilliseconds() > 0 ); } while( countdown.GetMilliseconds() > 0 );
@ -198,7 +203,7 @@ bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
throw Exception::ThreadTimedOut(); throw Exception::ThreadTimedOut();
#else #else
return FullBlockingAcquire(); return AcquireWithoutYield();
#endif #endif
} }

View File

@ -18,6 +18,7 @@
#include "Threading.h" #include "Threading.h"
#include "wxBaseTools.h" #include "wxBaseTools.h"
#include "wxGuiTools.h"
#include "ThreadingInternal.h" #include "ThreadingInternal.h"
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -59,12 +60,13 @@ void Threading::Semaphore::Post( int multiple )
#endif #endif
} }
void Threading::Semaphore::WaitRaw() void Threading::Semaphore::WaitWithoutYield()
{ {
pxAssertMsg( !wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead." );
sem_wait( &m_sema ); sem_wait( &m_sema );
} }
bool Threading::Semaphore::WaitRaw( const wxTimeSpan& timeout ) bool Threading::Semaphore::WaitWithoutYield( const wxTimeSpan& timeout )
{ {
wxDateTime megafail( wxDateTime::UNow() + timeout ); wxDateTime megafail( wxDateTime::UNow() + timeout );
const timespec fail = { megafail.GetTicks(), megafail.GetMillisecond() * 1000000 }; const timespec fail = { megafail.GetTicks(), megafail.GetMillisecond() * 1000000 };
@ -85,24 +87,26 @@ void Threading::Semaphore::Wait()
#if wxUSE_GUI #if wxUSE_GUI
if( !wxThread::IsMain() || (wxTheApp == NULL) ) if( !wxThread::IsMain() || (wxTheApp == NULL) )
{ {
WaitRaw(); sem_wait( &m_sema );
} }
else if( _WaitGui_RecursionGuard( "Semaphore::Wait" ) ) else if( _WaitGui_RecursionGuard( "Semaphore::Wait" ) )
{ {
if( !WaitRaw(def_yieldgui_interval) ) // default is 4 seconds ScopedBusyCursor hourglass( Cursor_ReallyBusy );
if( !WaitWithoutYield(def_yieldgui_interval) ) // default is 4 seconds
throw Exception::ThreadTimedOut(); throw Exception::ThreadTimedOut();
} }
else else
{ {
while( !WaitRaw( def_yieldgui_interval ) ) ScopedBusyCursor hourglass( Cursor_KindaBusy );
while( !WaitWithoutYield( def_yieldgui_interval ) )
wxTheApp->Yield( true ); wxTheApp->Yield( true );
} }
#else #else
WaitRaw(); sem_wait( &m_sema );
#endif #endif
} }
// This is a wxApp-safe implementation of WaitRaw, which makes sure and executes the App's // This is a wxApp-safe implementation of WaitWithoutYield, which makes sure and executes the App's
// pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that // pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that
// user input continues to be handled and that windows continue to repaint. If the Wait is // user input continues to be handled and that windows continue to repaint. If the Wait is
// called from another thread, no message pumping is performed. // called from another thread, no message pumping is performed.
@ -119,23 +123,25 @@ bool Threading::Semaphore::Wait( const wxTimeSpan& timeout )
#if wxUSE_GUI #if wxUSE_GUI
if( !wxThread::IsMain() || (wxTheApp == NULL) ) if( !wxThread::IsMain() || (wxTheApp == NULL) )
{ {
return WaitRaw( timeout ); return WaitWithoutYield( timeout );
} }
else if( _WaitGui_RecursionGuard( "Semaphore::Wait(timeout)" ) ) else if( _WaitGui_RecursionGuard( "Semaphore::Wait(timeout)" ) )
{ {
ScopedBusyCursor hourglass( Cursor_ReallyBusy );
if( timeout > def_deadlock_timeout ) if( timeout > def_deadlock_timeout )
{ {
if( WaitRaw(def_deadlock_timeout) ) return true; if( WaitWithoutYield(def_deadlock_timeout) ) return true;
throw Exception::ThreadTimedOut(); throw Exception::ThreadTimedOut();
} }
return WaitRaw( timeout ); return WaitWithoutYield( timeout );
} }
else else
{ {
ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown( (timeout) ); wxTimeSpan countdown( (timeout) );
do { do {
if( WaitRaw( def_yieldgui_interval ) ) break; if( WaitWithoutYield( def_yieldgui_interval ) ) break;
wxTheApp->Yield(true); wxTheApp->Yield(true);
countdown -= def_yieldgui_interval; countdown -= def_yieldgui_interval;
} while( countdown.GetMilliseconds() > 0 ); } while( countdown.GetMilliseconds() > 0 );
@ -143,7 +149,7 @@ bool Threading::Semaphore::Wait( const wxTimeSpan& timeout )
return countdown.GetMilliseconds() > 0; return countdown.GetMilliseconds() > 0;
} }
#else #else
return WaitRaw( timeout ); return WaitWithoutYield( timeout );
#endif #endif
} }
@ -152,14 +158,14 @@ bool Threading::Semaphore::Wait( const wxTimeSpan& timeout )
// the stack and passed to another thread via GUI message or such, avoiding complications where // the stack and passed to another thread via GUI message or such, avoiding complications where
// the thread might be canceled and the stack value becomes invalid. // the thread might be canceled and the stack value becomes invalid.
// //
// Performance note: this function has quite a bit more overhead compared to Semaphore::WaitRaw(), so // Performance note: this function has quite a bit more overhead compared to Semaphore::WaitWithoutYield(), so
// consider manually specifying the thread as uncancellable and using WaitRaw() instead if you need // consider manually specifying the thread as uncancellable and using WaitWithoutYield() instead if you need
// to do a lot of no-cancel waits in a tight loop worker thread, for example. // to do a lot of no-cancel waits in a tight loop worker thread, for example.
void Threading::Semaphore::WaitNoCancel() void Threading::Semaphore::WaitNoCancel()
{ {
int oldstate; int oldstate;
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate ); pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
WaitRaw(); WaitWithoutYield();
pthread_setcancelstate( oldstate, NULL ); pthread_setcancelstate( oldstate, NULL );
} }
@ -167,7 +173,7 @@ void Threading::Semaphore::WaitNoCancel( const wxTimeSpan& timeout )
{ {
int oldstate; int oldstate;
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate ); pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldstate );
WaitRaw( timeout ); WaitWithoutYield( timeout );
pthread_setcancelstate( oldstate, NULL ); pthread_setcancelstate( oldstate, NULL );
} }

View File

@ -496,7 +496,7 @@ void Threading::BaseTaskThread::WaitForResult()
#ifdef wxUSE_GUI #ifdef wxUSE_GUI
m_post_TaskComplete.Wait(); m_post_TaskComplete.Wait();
#else #else
m_post_TaskComplete.WaitRaw(); m_post_TaskComplete.WaitWithoutYield();
#endif #endif
m_post_TaskComplete.Reset(); m_post_TaskComplete.Reset();
@ -507,7 +507,7 @@ void Threading::BaseTaskThread::ExecuteTaskInThread()
while( !m_Done ) while( !m_Done )
{ {
// Wait for a job -- or get a pthread_cancel. I'm easy. // Wait for a job -- or get a pthread_cancel. I'm easy.
m_sem_event.WaitRaw(); m_sem_event.WaitWithoutYield();
Task(); Task();
m_lock_TaskComplete.Acquire(); m_lock_TaskComplete.Acquire();

View File

@ -16,6 +16,7 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "wxGuiTools.h" #include "wxGuiTools.h"
#include <wx/app.h>
#include <wx/window.h> #include <wx/window.h>
// Returns FALSE if the window position is considered invalid, which means that it's title // Returns FALSE if the window position is considered invalid, which means that it's title
@ -39,3 +40,70 @@ wxRect wxGetDisplayArea()
return wxRect( wxPoint(), wxGetDisplaySize() ); return wxRect( wxPoint(), wxGetDisplaySize() );
} }
// --------------------------------------------------------------------------------------
// ScopedBusyCursor Implementations
// --------------------------------------------------------------------------------------
std::stack<BusyCursorType> ScopedBusyCursor::m_cursorStack;
BusyCursorType ScopedBusyCursor::m_defBusyType;
ScopedBusyCursor::ScopedBusyCursor( BusyCursorType busytype )
{
pxAssert( wxTheApp != NULL );
BusyCursorType curtype = Cursor_NotBusy;
if( !m_cursorStack.empty() )
curtype = m_cursorStack.top();
if( curtype < busytype )
SetManualBusyCursor( curtype=busytype );
m_cursorStack.push( curtype );
}
ScopedBusyCursor::~ScopedBusyCursor() throw()
{
if( !pxAssert( wxTheApp != NULL ) ) return;
if( !pxAssert( !m_cursorStack.empty() ) )
{
SetManualBusyCursor( m_defBusyType );
return;
}
BusyCursorType curtype = m_cursorStack.top();
m_cursorStack.pop();
if( m_cursorStack.empty() )
SetManualBusyCursor( m_defBusyType );
else if( m_cursorStack.top() != curtype )
SetManualBusyCursor( m_cursorStack.top() );
}
void ScopedBusyCursor::SetDefault( BusyCursorType busytype )
{
if( busytype == m_defBusyType ) return;
m_defBusyType = busytype;
if( m_cursorStack.empty() )
SetManualBusyCursor( busytype );
}
void ScopedBusyCursor::SetManualBusyCursor( BusyCursorType busytype )
{
switch( busytype )
{
case Cursor_NotBusy: wxSetCursor( wxNullCursor ); break;
case Cursor_KindaBusy: wxSetCursor( StockCursors.GetArrowWait() ); break;
case Cursor_ReallyBusy: wxSetCursor( *wxHOURGLASS_CURSOR ); break;
}
}
const wxCursor& MoreStockCursors::GetArrowWait()
{
if( !m_arrowWait )
m_arrowWait = new wxCursor( wxCURSOR_ARROWWAIT );
return *m_arrowWait;
}
MoreStockCursors StockCursors;

View File

@ -246,7 +246,7 @@ void mtgsThreadObject::ExecuteTaskInThread()
// is very optimized (only 1 instruction test in most cases), so no point in trying // is very optimized (only 1 instruction test in most cases), so no point in trying
// to avoid it. // to avoid it.
m_sem_event.WaitRaw(); m_sem_event.WaitWithoutYield();
StateCheckInThread(); StateCheckInThread();
m_RingBufferIsBusy = true; m_RingBufferIsBusy = true;

View File

@ -232,7 +232,7 @@ void SysCoreThread::ExecuteTaskInThread()
tls_coreThread = this; tls_coreThread = this;
m_sem_event.WaitRaw(); m_sem_event.WaitWithoutYield();
PCSX2_PAGEFAULT_PROTECT { PCSX2_PAGEFAULT_PROTECT {
StateCheckInThread(); StateCheckInThread();
Cpu->Execute(); Cpu->Execute();

View File

@ -40,7 +40,7 @@ void SysThreadBase::Start()
Sleep( 1 ); Sleep( 1 );
if( !m_ResumeEvent.WaitRaw( wxTimeSpan(0, 0, 1, 500) ) ) if( !m_ResumeEvent.WaitWithoutYield( wxTimeSpan(0, 0, 1, 500) ) )
{ {
RethrowException(); RethrowException();
if( pxAssertDev( m_ExecMode == ExecMode_Closing, "Unexpected thread status during SysThread startup." ) ) if( pxAssertDev( m_ExecMode == ExecMode_Closing, "Unexpected thread status during SysThread startup." ) )
@ -103,16 +103,19 @@ bool SysThreadBase::Suspend( bool isBlocking )
{ {
ScopedLock locker( m_ExecModeMutex ); ScopedLock locker( m_ExecModeMutex );
// Check again -- status could have changed since above. switch( m_ExecMode )
if( m_ExecMode == ExecMode_Closed ) return false;
if( m_ExecMode == ExecMode_Pausing || m_ExecMode == ExecMode_Paused )
throw Exception::CancelEvent( "Another thread is pausing the VM state." );
if( m_ExecMode == ExecMode_Opened )
{ {
m_ExecMode = ExecMode_Closing; // Check again -- status could have changed since above.
retval = true; case ExecMode_Closed: return false;
case ExecMode_Pausing:
case ExecMode_Paused:
throw Exception::CancelEvent( "Another thread is pausing the VM state." );
case ExecMode_Opened:
m_ExecMode = ExecMode_Closing;
retval = true;
break;
} }
pxAssertDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." ); pxAssertDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." );
@ -198,7 +201,7 @@ void SysThreadBase::Resume()
// The entire state coming out of a Wait is indeterminate because of user input // The entire state coming out of a Wait is indeterminate because of user input
// and pending messages being handled. So after each call we do some seemingly redundant // and pending messages being handled. So after each call we do some seemingly redundant
// sanity checks against m_ExecMode/m_Running status, and if something doesn't feel // sanity checks against m_ExecMode/m_Running status, and if something doesn't feel
// right, we should abort. // right, we should abort; the user may have canceled the action before it even finished.
switch( m_ExecMode ) switch( m_ExecMode )
{ {
@ -206,10 +209,6 @@ void SysThreadBase::Resume()
case ExecMode_NoThreadYet: case ExecMode_NoThreadYet:
{ {
/*static int __Guard = 0;
RecursionGuard guard( __Guard );
if( guard.IsReentrant() ) return;*/
Start(); Start();
if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) ) if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) )
throw Exception::ThreadCreationError(); throw Exception::ThreadCreationError();
@ -290,7 +289,7 @@ void SysThreadBase::StateCheckInThread()
case ExecMode_Paused: case ExecMode_Paused:
while( m_ExecMode == ExecMode_Paused ) while( m_ExecMode == ExecMode_Paused )
m_ResumeEvent.WaitRaw(); m_ResumeEvent.WaitWithoutYield();
m_RunningLock.Acquire(); m_RunningLock.Acquire();
OnResumeInThread( false ); OnResumeInThread( false );
@ -307,7 +306,7 @@ void SysThreadBase::StateCheckInThread()
case ExecMode_Closed: case ExecMode_Closed:
while( m_ExecMode == ExecMode_Closed ) while( m_ExecMode == ExecMode_Closed )
m_ResumeEvent.WaitRaw(); m_ResumeEvent.WaitWithoutYield();
m_RunningLock.Acquire(); m_RunningLock.Acquire();
OnResumeInThread( true ); OnResumeInThread( true );

View File

@ -29,6 +29,8 @@ AppCoreThread::~AppCoreThread() throw()
void AppCoreThread::Reset() void AppCoreThread::Reset()
{ {
ScopedBusyCursor::SetDefault( Cursor_KindaBusy );
_parent::Reset(); _parent::Reset();
wxCommandEvent evt( pxEVT_CoreThreadStatus ); wxCommandEvent evt( pxEVT_CoreThreadStatus );
@ -38,6 +40,7 @@ void AppCoreThread::Reset()
bool AppCoreThread::Suspend( bool isBlocking ) bool AppCoreThread::Suspend( bool isBlocking )
{ {
ScopedBusyCursor::SetDefault( Cursor_KindaBusy );
bool retval = _parent::Suspend( isBlocking ); bool retval = _parent::Suspend( isBlocking );
// Clear the sticky key statuses, because hell knows what'll change while the PAD // Clear the sticky key statuses, because hell knows what'll change while the PAD
@ -67,6 +70,7 @@ void AppCoreThread::Resume()
return; return;
} }
ScopedBusyCursor::SetDefault( Cursor_KindaBusy );
_parent::Resume(); _parent::Resume();
if( m_ExecMode != ExecMode_Opened ) if( m_ExecMode != ExecMode_Opened )

View File

@ -138,6 +138,7 @@ void Pcsx2App::Ping() const
void Pcsx2App::OnCoreThreadStatus( wxCommandEvent& evt ) void Pcsx2App::OnCoreThreadStatus( wxCommandEvent& evt )
{ {
m_evtsrc_CoreThreadStatus.Dispatch( evt ); m_evtsrc_CoreThreadStatus.Dispatch( evt );
ScopedBusyCursor::SetDefault( Cursor_NotBusy );
} }
void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt ) void Pcsx2App::OnSemaphorePing( wxCommandEvent& evt )
@ -497,9 +498,11 @@ void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override
// This message performs actual system execution (as dictated by SysExecute variants). // This message performs actual system execution (as dictated by SysExecute variants).
// It is implemented as a message handler so that it can be triggered in response to // It is implemented as a message handler so that it can be triggered in response to
// the completion of other dependent activites, namely loading plugins. // the completion of other dependent activities, namely loading plugins.
void Pcsx2App::OnSysExecute( wxCommandEvent& evt ) void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
{ {
CoreThread.ReleaseResumeLock();
if( sys_resume_lock > 0 ) if( sys_resume_lock > 0 )
{ {
Console.WriteLn( "SysExecute: State is locked, ignoring Execute request!" ); Console.WriteLn( "SysExecute: State is locked, ignoring Execute request!" );
@ -520,7 +523,6 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
if( !CoreThread.HasValidState() ) if( !CoreThread.HasValidState() )
CoreThread.SetElfOverride( _sysexec_elf_override ); CoreThread.SetElfOverride( _sysexec_elf_override );
CoreThread.ReleaseResumeLock();
CoreThread.Resume(); CoreThread.Resume();
} }
@ -528,6 +530,7 @@ void Pcsx2App::OnSysExecute( wxCommandEvent& evt )
void Pcsx2App::SysReset() void Pcsx2App::SysReset()
{ {
CoreThread.Reset(); CoreThread.Reset();
CoreThread.ReleaseResumeLock();
m_CorePlugins = NULL; m_CorePlugins = NULL;
} }

View File

@ -410,8 +410,8 @@ namespace Panels
SafeList<EnumeratedPluginInfo> Results; // array of plugin results. SafeList<EnumeratedPluginInfo> Results; // array of plugin results.
protected: protected:
PluginSelectorPanel& m_master; PluginSelectorPanel& m_master;
ScopedBusyCursor m_hourglass;
public: public:
virtual ~EnumThread() throw() virtual ~EnumThread() throw()
{ {

View File

@ -545,6 +545,7 @@ Panels::PluginSelectorPanel::EnumThread::EnumThread( PluginSelectorPanel& master
PersistentThread() PersistentThread()
, Results( master.FileCount(), L"PluginSelectorResults" ) , Results( master.FileCount(), L"PluginSelectorResults" )
, m_master( master ) , m_master( master )
, m_hourglass( Cursor_KindaBusy )
{ {
Results.MatchLengthToAllocatedSize(); Results.MatchLengthToAllocatedSize();
} }

View File

@ -93,10 +93,10 @@ public:
PluginManager* Result; PluginManager* Result;
protected: protected:
wxString m_folders[PluginId_Count]; wxString m_folders[PluginId_Count];
ScopedBusyCursor m_hourglass;
public: public:
LoadPluginsTask( const wxString (&folders)[PluginId_Count] ) : Result( NULL ) LoadPluginsTask( const wxString (&folders)[PluginId_Count] ) : Result( NULL ), m_hourglass( Cursor_KindaBusy )
{ {
for(int i=0; i<PluginId_Count; ++i ) for(int i=0; i<PluginId_Count; ++i )
m_folders[i] = folders[i]; m_folders[i] = folders[i];