mirror of https://github.com/PCSX2/pcsx2.git
UI Bugfixes:
* Fixed several obscure deadlock issues. * Savestate actions block; such that only one load or save is permitted at a time. * Savestates now work through temp files, so that the existing file is not corrupted in case errors occur. * Exiting the emu while a savestate is saving will still save the state before completely quitting. * Plugin init errors are handled more gracefully. Developer Notes: * Added some event diagnostic trace logging stuff. * More preliminary work on memorycards -- moved them to their own dialog box and started implementing things, but still a lot of work to do before it's ready for use. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2936 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
b9c8ac3ead
commit
1507d72cad
|
@ -161,6 +161,7 @@
|
|||
<Unit filename="../../include/Utilities/ScopedPtr.h" />
|
||||
<Unit filename="../../include/Utilities/StringHelpers.h" />
|
||||
<Unit filename="../../include/Utilities/Threading.h" />
|
||||
<Unit filename="../../include/Utilities/ThreadingDialogs.h" />
|
||||
<Unit filename="../../include/Utilities/lnx_memzero.h" />
|
||||
<Unit filename="../../include/Utilities/pxCheckBox.h" />
|
||||
<Unit filename="../../include/Utilities/pxEvents.h" />
|
||||
|
@ -188,6 +189,7 @@
|
|||
<Unit filename="../../src/Utilities/Semaphore.cpp" />
|
||||
<Unit filename="../../src/Utilities/StringHelpers.cpp" />
|
||||
<Unit filename="../../src/Utilities/ThreadTools.cpp" />
|
||||
<Unit filename="../../src/Utilities/ThreadingDialogs.cpp" />
|
||||
<Unit filename="../../src/Utilities/ThreadingInternal.h" />
|
||||
<Unit filename="../../src/Utilities/pxCheckBox.cpp" />
|
||||
<Unit filename="../../src/Utilities/pxRadioPanel.cpp" />
|
||||
|
|
|
@ -430,6 +430,10 @@
|
|||
RelativePath="..\..\src\Utilities\Semaphore.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\Utilities\ThreadingDialogs.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\Utilities\ThreadingInternal.h"
|
||||
>
|
||||
|
@ -568,6 +572,10 @@
|
|||
RelativePath="..\..\include\Utilities\Threading.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\ThreadingDialogs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\TlsVariable.inl"
|
||||
>
|
||||
|
|
|
@ -128,11 +128,24 @@ namespace Exception
|
|||
// The text string will be passed through the translator, so if it's int he gettext database
|
||||
// it will be optionally translated.
|
||||
//
|
||||
// BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates
|
||||
// ambiguity errors on virtual inheritence (it really shouldn't!). So I have to force it to the
|
||||
// BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air
|
||||
//
|
||||
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
|
||||
//
|
||||
#define DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
virtual ~classname() throw() {} \
|
||||
virtual void Rethrow() const { throw *this; } \
|
||||
virtual BaseException* Clone() const { return new classname( *this ); }
|
||||
|
||||
// This is here because MSVC's support for covariant return types on Clone() is broken, and will
|
||||
// not work with virtual class inheritance (see DEFINE_EXCEPTION_COPYTORS for details)
|
||||
#define DEFINE_EXCEPTION_COPYTORS_COVARIANT( classname ) \
|
||||
virtual ~classname() throw() {} \
|
||||
virtual void Rethrow() const { throw *this; } \
|
||||
virtual classname* Clone() const { return new classname( *this ); }
|
||||
|
||||
#define DEFINE_RUNTIME_EXCEPTION( classname, defmsg ) \
|
||||
DEFINE_EXCEPTION_COPYTORS( classname ) \
|
||||
\
|
||||
|
|
|
@ -312,6 +312,10 @@ namespace Threading
|
|||
explicit ScopedLock( const Mutex& locker );
|
||||
void AssignAndLock( const Mutex& locker );
|
||||
void AssignAndLock( const Mutex* locker );
|
||||
|
||||
void Assign( const Mutex& locker );
|
||||
void Assign( const Mutex* locker );
|
||||
|
||||
void Release();
|
||||
void Acquire();
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/* 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 "wxAppWithHelpers.h"
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE(pxEvt_ThreadedTaskComplete, -1)
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
namespace Threading
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
// WaitForTaskDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This dialog is displayed whenever the main thread is recursively waiting on multiple
|
||||
// mutexes or semaphores. wxwidgets does not support recursive yielding to pending events
|
||||
// but it *does* support opening a modal dialog, which disables the interface (preventing
|
||||
// the user from starting additional actions), and processes messages (allowing the system
|
||||
// to continue to manage threads and process logging).
|
||||
//
|
||||
class WaitForTaskDialog : public wxDialogWithHelpers
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS_NO_COPY(WaitForTaskDialog)
|
||||
|
||||
typedef wxDialogWithHelpers _parent;
|
||||
|
||||
protected:
|
||||
SynchronousActionState m_sync;
|
||||
|
||||
public:
|
||||
WaitForTaskDialog( const wxString& title=wxEmptyString, const wxString& heading=wxEmptyString );
|
||||
virtual ~WaitForTaskDialog() throw() {}
|
||||
virtual int ShowModal();
|
||||
|
||||
protected:
|
||||
void OnTaskComplete( wxCommandEvent& evt );
|
||||
//void OnTimer( wxTimerEvent& evt );
|
||||
};
|
||||
|
||||
}
|
|
@ -31,12 +31,12 @@ class SynchronousActionState
|
|||
DeclareNoncopyableObject( SynchronousActionState );
|
||||
|
||||
protected:
|
||||
bool m_posted;
|
||||
Threading::Semaphore m_sema;
|
||||
bool m_posted;
|
||||
Threading::Semaphore m_sema;
|
||||
ScopedPtr<BaseException> m_exception;
|
||||
|
||||
public:
|
||||
sptr return_value;
|
||||
sptr return_value;
|
||||
|
||||
SynchronousActionState()
|
||||
{
|
||||
|
@ -59,35 +59,12 @@ public:
|
|||
Threading::Semaphore& GetSemaphore() { return m_sema; }
|
||||
const Threading::Semaphore& GetSemaphore() const { return m_sema; }
|
||||
|
||||
void RethrowException() const
|
||||
{
|
||||
if( m_exception ) m_exception->Rethrow();
|
||||
}
|
||||
|
||||
int WaitForResult()
|
||||
{
|
||||
m_sema.WaitNoCancel();
|
||||
RethrowException();
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void PostResult( int res )
|
||||
{
|
||||
return_value = res;
|
||||
PostResult();
|
||||
}
|
||||
|
||||
void ClearResult()
|
||||
{
|
||||
m_posted = false;
|
||||
}
|
||||
|
||||
void PostResult()
|
||||
{
|
||||
if( m_posted ) return;
|
||||
m_posted = true;
|
||||
m_sema.Post();
|
||||
}
|
||||
void RethrowException() const;
|
||||
int WaitForResult();
|
||||
int WaitForResult_NoExceptions();
|
||||
void PostResult( int res );
|
||||
void ClearResult();
|
||||
void PostResult();
|
||||
};
|
||||
|
||||
|
||||
|
@ -117,7 +94,7 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// pxInvokeActionEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
class pxInvokeActionEvent : public wxEvent, public virtual IActionInvocation
|
||||
class pxInvokeActionEvent : public wxEvent
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxInvokeActionEvent)
|
||||
|
||||
|
@ -143,10 +120,10 @@ public:
|
|||
virtual void SetException( BaseException* ex );
|
||||
void SetException( const BaseException& ex );
|
||||
|
||||
virtual void InvokeAction();
|
||||
virtual void _DoInvokeEvent();
|
||||
|
||||
protected:
|
||||
virtual void _DoInvoke() {};
|
||||
virtual void InvokeEvent() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -168,11 +145,14 @@ public:
|
|||
|
||||
pxExceptionEvent( const BaseException& ex );
|
||||
|
||||
virtual ~pxExceptionEvent() throw() { }
|
||||
virtual ~pxExceptionEvent() throw()
|
||||
{
|
||||
}
|
||||
|
||||
virtual pxExceptionEvent *Clone() const { return new pxExceptionEvent(*this); }
|
||||
|
||||
protected:
|
||||
void _DoInvoke();
|
||||
void InvokeEvent();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -226,7 +206,7 @@ public:
|
|||
BaseMessageBoxEvent( const BaseMessageBoxEvent& event );
|
||||
|
||||
protected:
|
||||
virtual void _DoInvoke();
|
||||
virtual void InvokeEvent();
|
||||
virtual int _DoDialog() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -315,6 +315,7 @@ public:
|
|||
|
||||
void Init();
|
||||
void AddOkCancel( wxSizer& sizer, bool hasApply=false );
|
||||
void AddOkCancel( wxSizer* sizer=NULL, bool hasApply=false );
|
||||
|
||||
virtual void SmartCenterFit();
|
||||
virtual int ShowModal();
|
||||
|
|
|
@ -141,9 +141,6 @@ bool Threading::Mutex::TryAcquire()
|
|||
// 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.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
void Threading::Mutex::Acquire()
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
|
@ -151,23 +148,22 @@ void Threading::Mutex::Acquire()
|
|||
{
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
}
|
||||
else if( _WaitGui_RecursionGuard( "Mutex::Acquire" ) )
|
||||
else if( _WaitGui_RecursionGuard( L"Mutex::Acquire" ) )
|
||||
{
|
||||
AcquireWithoutYield();
|
||||
ScopedBusyCursor hourglass( Cursor_ReallyBusy );
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
}
|
||||
else
|
||||
{
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
while( !AcquireWithoutYield(def_yieldgui_interval) )
|
||||
wxTheApp->Yield( true );
|
||||
YieldToMain();
|
||||
}
|
||||
#else
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
#endif
|
||||
}
|
||||
|
||||
// Exceptions:
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
|
@ -175,19 +171,19 @@ bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
|
|||
{
|
||||
return AcquireWithoutYield(timeout);
|
||||
}
|
||||
else if( _WaitGui_RecursionGuard( "Mutex::Acquire(timeout)" ) )
|
||||
else if( _WaitGui_RecursionGuard( L"Mutex::TimedAcquire" ) )
|
||||
{
|
||||
ScopedBusyCursor hourglass( Cursor_ReallyBusy );
|
||||
return AcquireWithoutYield( timeout );
|
||||
}
|
||||
else
|
||||
{
|
||||
ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown( (timeout) );
|
||||
|
||||
do {
|
||||
if( AcquireWithoutYield( def_yieldgui_interval ) ) break;
|
||||
wxTheApp->Yield(true);
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while( countdown.GetMilliseconds() > 0 );
|
||||
|
||||
|
@ -206,9 +202,6 @@ bool Threading::Mutex::Acquire( const wxTimeSpan& timeout )
|
|||
//
|
||||
// Implemented internally as a simple Acquire/Release pair.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
void Threading::Mutex::Wait()
|
||||
{
|
||||
Acquire();
|
||||
|
@ -228,9 +221,6 @@ void Threading::Mutex::WaitWithoutYield()
|
|||
// true if the mutex was freed and is in an unlocked state; or false if the wait timed out
|
||||
// and the mutex is still locked by another thread.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
bool Threading::Mutex::Wait( const wxTimeSpan& timeout )
|
||||
{
|
||||
if( Acquire(timeout) )
|
||||
|
@ -285,6 +275,16 @@ void Threading::ScopedLock::AssignAndLock( const Mutex* locker )
|
|||
m_lock->Acquire();
|
||||
}
|
||||
|
||||
void Threading::ScopedLock::Assign( const Mutex& locker )
|
||||
{
|
||||
m_lock = const_cast<Mutex*>(&locker);
|
||||
}
|
||||
|
||||
void Threading::ScopedLock::Assign( const Mutex* locker )
|
||||
{
|
||||
m_lock = const_cast<Mutex*>(locker);
|
||||
}
|
||||
|
||||
// Provides manual unlocking of a scoped lock prior to object destruction.
|
||||
void Threading::ScopedLock::Release()
|
||||
{
|
||||
|
|
|
@ -79,9 +79,6 @@ bool Threading::Semaphore::WaitWithoutYield( const wxTimeSpan& timeout )
|
|||
// user input continues to be handled and that windoes continue to repaint. If the Wait is
|
||||
// called from another thread, no message pumping is performed.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
void Threading::Semaphore::Wait()
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
|
@ -89,16 +86,16 @@ void Threading::Semaphore::Wait()
|
|||
{
|
||||
sem_wait( &m_sema );
|
||||
}
|
||||
else if( _WaitGui_RecursionGuard( "Semaphore::Wait" ) )
|
||||
else if( _WaitGui_RecursionGuard( L"Semaphore::Wait" ) )
|
||||
{
|
||||
ScopedBusyCursor hourglass( Cursor_ReallyBusy );
|
||||
WaitWithoutYield();
|
||||
sem_wait( &m_sema );
|
||||
}
|
||||
else
|
||||
{
|
||||
ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
while( !WaitWithoutYield( def_yieldgui_interval ) )
|
||||
wxTheApp->Yield( true );
|
||||
YieldToMain();
|
||||
}
|
||||
#else
|
||||
sem_wait( &m_sema );
|
||||
|
@ -114,9 +111,6 @@ void Threading::Semaphore::Wait()
|
|||
// false if the wait timed out before the semaphore was signaled, or true if the signal was
|
||||
// reached prior to timeout.
|
||||
//
|
||||
// Exceptions:
|
||||
// ThreadDeadlock - See description of ThreadDeadlock for details
|
||||
//
|
||||
bool Threading::Semaphore::Wait( const wxTimeSpan& timeout )
|
||||
{
|
||||
#if wxUSE_GUI
|
||||
|
@ -124,19 +118,19 @@ bool Threading::Semaphore::Wait( const wxTimeSpan& timeout )
|
|||
{
|
||||
return WaitWithoutYield( timeout );
|
||||
}
|
||||
else if( _WaitGui_RecursionGuard( "Semaphore::Wait(timeout)" ) )
|
||||
else if( _WaitGui_RecursionGuard( L"Semaphore::TimedWait" ) )
|
||||
{
|
||||
ScopedBusyCursor hourglass( Cursor_ReallyBusy );
|
||||
return WaitWithoutYield( timeout );
|
||||
}
|
||||
else
|
||||
{
|
||||
ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
|
||||
wxTimeSpan countdown( (timeout) );
|
||||
|
||||
do {
|
||||
if( WaitWithoutYield( def_yieldgui_interval ) ) break;
|
||||
wxTheApp->Yield(true);
|
||||
YieldToMain();
|
||||
countdown -= def_yieldgui_interval;
|
||||
} while( countdown.GetMilliseconds() > 0 );
|
||||
|
||||
|
|
|
@ -125,8 +125,10 @@ void Threading::pxYield( int ms )
|
|||
// (intended for internal use only)
|
||||
// Returns true if the Wait is recursive, or false if the Wait is safe and should be
|
||||
// handled via normal yielding methods.
|
||||
bool Threading::_WaitGui_RecursionGuard( const char* guardname )
|
||||
bool Threading::_WaitGui_RecursionGuard( const wxChar* name )
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
|
||||
// In order to avoid deadlock we need to make sure we cut some time to handle messages.
|
||||
// But this can result in recursive yield calls, which would crash the app. Protect
|
||||
// against them here and, if recursion is detected, perform a standard blocking wait.
|
||||
|
@ -134,12 +136,11 @@ bool Threading::_WaitGui_RecursionGuard( const char* guardname )
|
|||
static int __Guard = 0;
|
||||
RecursionGuard guard( __Guard );
|
||||
|
||||
if( guard.IsReentrant() )
|
||||
{
|
||||
Console.WriteLn( "(Thread Log) Possible yield recursion detected in %s; performing blocking wait.", guardname );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
//if( pxAssertDev( !guard.IsReentrant(), "Recursion during UI-bound threading wait object." ) ) return false;
|
||||
|
||||
if( !guard.IsReentrant() ) return false;
|
||||
Console.WriteLn( "(Thread:%s) Yield recursion in %s; opening modal dialog.", pxGetCurrentThreadName().c_str(), name );
|
||||
return true;
|
||||
}
|
||||
|
||||
__forceinline void Threading::Timeslice()
|
||||
|
@ -383,11 +384,26 @@ void Threading::PersistentThread::RethrowException() const
|
|||
m_except->Rethrow();
|
||||
}
|
||||
|
||||
static bool m_BlockDeletions = false;
|
||||
|
||||
bool Threading::AllowDeletions()
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
return !m_BlockDeletions;
|
||||
}
|
||||
|
||||
void Threading::YieldToMain()
|
||||
{
|
||||
m_BlockDeletions = true;
|
||||
wxTheApp->Yield( true );
|
||||
m_BlockDeletions = false;
|
||||
}
|
||||
|
||||
void Threading::PersistentThread::_selfRunningTest( const wxChar* name ) const
|
||||
{
|
||||
if( HasPendingException() )
|
||||
{
|
||||
Console.Error( L"(Thread Error) An exception was thrown from blocking thread '%s' while waiting on a %s.",
|
||||
Console.Error( L"(Thread:%s) An exception was thrown while waiting on a %s.",
|
||||
GetName().c_str(), name
|
||||
);
|
||||
RethrowException();
|
||||
|
@ -400,6 +416,13 @@ void Threading::PersistentThread::_selfRunningTest( const wxChar* name ) const
|
|||
GetName().c_str(), name )
|
||||
);
|
||||
}
|
||||
|
||||
// Thread is still alive and kicking (for now) -- yield to other messages and hope
|
||||
// that impending chaos does not ensue. [it shouldn't since we block PersistentThread
|
||||
// objects from being deleted until outside the scope of a mutex/semaphore wait).
|
||||
|
||||
if( (wxTheApp != NULL) && wxThread::IsMain() && !_WaitGui_RecursionGuard( L"WaitForSelf" ) )
|
||||
Threading::YieldToMain();
|
||||
}
|
||||
|
||||
// This helper function is a deadlock-safe method of waiting on a semaphore in a PersistentThread. If the
|
||||
|
@ -666,7 +689,7 @@ void Threading::BaseTaskThread::WaitForResult()
|
|||
{
|
||||
if( m_detached || !m_running ) return;
|
||||
if( m_TaskPending )
|
||||
#ifdef wxUSE_GUI
|
||||
#if wxUSE_GUI
|
||||
m_post_TaskComplete.Wait();
|
||||
#else
|
||||
m_post_TaskComplete.WaitWithoutYield();
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* 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 "ThreadingDialogs.h"
|
||||
#include "pxStaticText.h"
|
||||
|
||||
|
||||
DEFINE_EVENT_TYPE(pxEvt_ThreadedTaskComplete);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// WaitForTaskDialog Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
IMPLEMENT_DYNAMIC_CLASS(WaitForTaskDialog, wxDialogWithHelpers)
|
||||
|
||||
Threading::WaitForTaskDialog::WaitForTaskDialog( const wxString& title, const wxString& heading )
|
||||
: wxDialogWithHelpers( NULL, _("Waiting for tasks..."), wxVERTICAL )
|
||||
//, m_Timer(this)
|
||||
{
|
||||
//m_sem = sem;
|
||||
//m_mutex = mutex;
|
||||
|
||||
wxString m_title( title );
|
||||
wxString m_heading( heading );
|
||||
|
||||
if( m_title.IsEmpty() ) m_title = _("Waiting for task...");
|
||||
if( m_heading.IsEmpty() ) m_heading = m_title;
|
||||
|
||||
Connect( pxEvt_ThreadedTaskComplete, wxCommandEventHandler(WaitForTaskDialog::OnTaskComplete) );
|
||||
|
||||
wxBoxSizer& paddedMsg( *new wxBoxSizer( wxHORIZONTAL ) );
|
||||
paddedMsg += 24;
|
||||
paddedMsg += Heading(m_heading);
|
||||
paddedMsg += 24;
|
||||
|
||||
*this += 12;
|
||||
*this += paddedMsg;
|
||||
*this += 12;
|
||||
|
||||
// TODO : Implement a cancel button. Not quite sure the best way to do
|
||||
// that, since it requires a thread or event handler context, or something.
|
||||
|
||||
//applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter;
|
||||
//applyDlg += 6;
|
||||
|
||||
//Connect( m_Timer.GetId(), wxEVT_TIMER, wxTimerEventHandler(WaitForTaskDialog::OnTimer) );
|
||||
//m_Timer.Start( 200 );
|
||||
//GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
|
||||
}
|
||||
|
||||
void Threading::WaitForTaskDialog::OnTaskComplete( wxCommandEvent& evt )
|
||||
{
|
||||
evt.Skip();
|
||||
|
||||
// Note: we don't throw exceptions from the pending task here.
|
||||
// Instead we wait until we exit the modal loop below -- this gives
|
||||
// the caller a chance to handle the exception themselves, and if
|
||||
// not the exception will still fall back on the standard app-level
|
||||
// exception handler.
|
||||
|
||||
// (this also avoids any sticky business with the modal dialog not getting
|
||||
// closed out right due to stack unwinding skipping dialog closure crap)
|
||||
|
||||
m_sync.WaitForResult_NoExceptions();
|
||||
EndModal( wxID_OK );
|
||||
}
|
||||
|
||||
int Threading::WaitForTaskDialog::ShowModal()
|
||||
{
|
||||
int result = _parent::ShowModal();
|
||||
m_sync.RethrowException();
|
||||
return result;
|
||||
}
|
|
@ -23,6 +23,9 @@ namespace Threading
|
|||
{
|
||||
extern const wxTimeSpan def_yieldgui_interval;
|
||||
|
||||
extern bool _WaitGui_RecursionGuard( const char* guardname );
|
||||
extern bool _WaitGui_RecursionGuard( const wxChar* name );
|
||||
|
||||
extern void YieldToMain();
|
||||
extern bool AllowDeletions();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
#include "wxAppWithHelpers.h"
|
||||
|
||||
#include "ThreadingInternal.h"
|
||||
#include "PersistentThread.h"
|
||||
|
||||
DEFINE_EVENT_TYPE( pxEvt_DeleteObject );
|
||||
|
@ -35,6 +36,47 @@ void BaseDeletableObject::DoDeletion()
|
|||
app->DeleteObject( *this );
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SynchronousActionState Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
void SynchronousActionState::RethrowException() const
|
||||
{
|
||||
if( m_exception ) m_exception->Rethrow();
|
||||
}
|
||||
|
||||
int SynchronousActionState::WaitForResult()
|
||||
{
|
||||
m_sema.WaitNoCancel();
|
||||
RethrowException();
|
||||
return return_value;
|
||||
}
|
||||
|
||||
int SynchronousActionState::WaitForResult_NoExceptions()
|
||||
{
|
||||
m_sema.WaitNoCancel();
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void SynchronousActionState::PostResult( int res )
|
||||
{
|
||||
return_value = res;
|
||||
PostResult();
|
||||
}
|
||||
|
||||
void SynchronousActionState::ClearResult()
|
||||
{
|
||||
m_posted = false;
|
||||
}
|
||||
|
||||
void SynchronousActionState::PostResult()
|
||||
{
|
||||
if( m_posted ) return;
|
||||
m_posted = true;
|
||||
m_sema.Post();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxInvokeActionEvent Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -181,7 +223,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
if( m_Method ) m_Method();
|
||||
}
|
||||
|
@ -197,7 +239,7 @@ pxExceptionEvent::pxExceptionEvent( const BaseException& ex )
|
|||
m_except = ex.Clone();
|
||||
}
|
||||
|
||||
void pxExceptionEvent::_DoInvoke()
|
||||
void pxExceptionEvent::InvokeEvent()
|
||||
{
|
||||
ScopedPtr<BaseException> deleteMe( m_except );
|
||||
if( deleteMe ) deleteMe->Rethrow();
|
||||
|
@ -322,12 +364,12 @@ void wxAppWithHelpers::CleanUp()
|
|||
_parent::CleanUp();
|
||||
}
|
||||
|
||||
void pxInvokeActionEvent::InvokeAction()
|
||||
void pxInvokeActionEvent::_DoInvokeEvent()
|
||||
{
|
||||
AffinityAssert_AllowFrom_MainUI();
|
||||
|
||||
try {
|
||||
_DoInvoke();
|
||||
InvokeEvent();
|
||||
}
|
||||
catch( BaseException& ex )
|
||||
{
|
||||
|
@ -387,10 +429,21 @@ void wxAppWithHelpers::IdleEventDispatcher( const char* action )
|
|||
|
||||
DbgCon.WriteLn( Color_Gray, "App IdleQueue (%s) -> %u events.", action, size );
|
||||
|
||||
std::vector<wxEvent*> postponed;
|
||||
|
||||
for( size_t i=0; i<size; ++i )
|
||||
ProcessEvent( *m_IdleEventQueue[i] );
|
||||
{
|
||||
if( !Threading::AllowDeletions() && (m_IdleEventQueue[i]->GetEventType() == pxEvt_DeleteThread) )
|
||||
postponed.push_back(m_IdleEventQueue[i]);
|
||||
else
|
||||
{
|
||||
lock.Release();
|
||||
ProcessEvent( *m_IdleEventQueue[i] );
|
||||
lock.Acquire();
|
||||
}
|
||||
}
|
||||
|
||||
m_IdleEventQueue.clear();
|
||||
m_IdleEventQueue = postponed;
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt )
|
||||
|
@ -464,7 +517,7 @@ void wxAppWithHelpers::ProcessAction( pxInvokeActionEvent& evt )
|
|||
sync.WaitForResult();
|
||||
}
|
||||
else
|
||||
evt.InvokeAction();
|
||||
evt._DoInvokeEvent();
|
||||
}
|
||||
|
||||
|
||||
|
@ -508,7 +561,7 @@ bool wxAppWithHelpers::OnInit()
|
|||
|
||||
void wxAppWithHelpers::OnInvokeAction( pxInvokeActionEvent& evt )
|
||||
{
|
||||
evt.InvokeAction(); // wow this is easy!
|
||||
evt._DoInvokeEvent(); // wow this is easy!
|
||||
}
|
||||
|
||||
void wxAppWithHelpers::OnDeleteObject( wxCommandEvent& evt )
|
||||
|
|
|
@ -263,6 +263,13 @@ void wxDialogWithHelpers::AddOkCancel( wxSizer &sizer, bool hasApply )
|
|||
s_buttons.Realize();
|
||||
}
|
||||
|
||||
void wxDialogWithHelpers::AddOkCancel( wxSizer *sizer, bool hasApply )
|
||||
{
|
||||
if( sizer == NULL ) sizer = GetSizer();
|
||||
pxAssume( sizer );
|
||||
AddOkCancel( *sizer, hasApply );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxPanelWithHelpers Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -377,6 +377,7 @@
|
|||
<Unit filename="../gui/Dialogs/ImportSettingsDialog.cpp" />
|
||||
<Unit filename="../gui/Dialogs/LogOptionsDialog.cpp" />
|
||||
<Unit filename="../gui/Dialogs/LogOptionsDialog.h" />
|
||||
<Unit filename="../gui/Dialogs/McdConfigDialog.cpp" />
|
||||
<Unit filename="../gui/Dialogs/ModalPopups.h" />
|
||||
<Unit filename="../gui/Dialogs/PickUserModeDialog.cpp" />
|
||||
<Unit filename="../gui/Dialogs/StuckThreadDialog.cpp" />
|
||||
|
@ -408,7 +409,7 @@
|
|||
<Unit filename="../gui/Panels/LogOptionsPanels.cpp" />
|
||||
<Unit filename="../gui/Panels/LogOptionsPanels.h" />
|
||||
<Unit filename="../gui/Panels/MemoryCardListPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/MemoryCardListView.h" />
|
||||
<Unit filename="../gui/Panels/MemoryCardPanels.h" />
|
||||
<Unit filename="../gui/Panels/MemoryCardsPanel.cpp" />
|
||||
<Unit filename="../gui/Panels/MiscPanelStuff.cpp" />
|
||||
<Unit filename="../gui/Panels/PathsPanel.cpp" />
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace Exception
|
|||
class PluginLoadError : public virtual PluginError, public virtual BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginLoadError )
|
||||
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginLoadError )
|
||||
|
||||
PluginLoadError( PluginsEnum_t pid, const wxString& objname, const char* eng );
|
||||
|
||||
|
@ -103,7 +103,7 @@ namespace Exception
|
|||
class PluginInitError : public virtual PluginError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginInitError )
|
||||
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginInitError )
|
||||
|
||||
explicit PluginInitError( PluginsEnum_t pid,
|
||||
const char* msg=wxLt("%s plugin failed to initialize. Your system may have insufficient memory or resources needed.") )
|
||||
|
@ -118,7 +118,7 @@ namespace Exception
|
|||
class PluginOpenError : public virtual PluginError
|
||||
{
|
||||
public:
|
||||
DEFINE_EXCEPTION_COPYTORS( PluginOpenError )
|
||||
DEFINE_EXCEPTION_COPYTORS_COVARIANT( PluginOpenError )
|
||||
|
||||
explicit PluginOpenError( PluginsEnum_t pid,
|
||||
const char* msg=wxLt("%s plugin failed to open. Your computer may have insufficient resources, or incompatible hardware/drivers.") )
|
||||
|
|
|
@ -79,9 +79,6 @@ void SysThreadBase::OnStart()
|
|||
// Suspension must cancel 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().
|
||||
//
|
||||
void SysThreadBase::Suspend( bool isBlocking )
|
||||
{
|
||||
if( IsSelf() || !IsRunning() ) return;
|
||||
|
|
|
@ -67,15 +67,19 @@ protected:
|
|||
|
||||
const wxString m_filename;
|
||||
ScopedPtr< SafeArray< u8 > > m_src_buffer;
|
||||
bool m_PendingSaveFlag;
|
||||
|
||||
BaseCompressThread( const wxString& file, SafeArray<u8>* srcdata, FnType_WriteCompressedHeader* writeHeader=NULL)
|
||||
: m_filename( file )
|
||||
, m_src_buffer( srcdata )
|
||||
{
|
||||
m_WriteHeaderInThread = writeHeader;
|
||||
m_WriteHeaderInThread = writeHeader;
|
||||
m_PendingSaveFlag = false;
|
||||
}
|
||||
|
||||
virtual ~BaseCompressThread() throw() {}
|
||||
virtual ~BaseCompressThread() throw();
|
||||
|
||||
void SetPendingSave();
|
||||
|
||||
public:
|
||||
wxString GetStreamName() const { return m_filename; }
|
||||
|
|
|
@ -20,6 +20,17 @@
|
|||
#include "ThreadedZipTools.h"
|
||||
|
||||
|
||||
BaseCompressThread::~BaseCompressThread() throw()
|
||||
{
|
||||
if( m_PendingSaveFlag ) wxGetApp().ClearPendingSave();
|
||||
}
|
||||
|
||||
void BaseCompressThread::SetPendingSave()
|
||||
{
|
||||
wxGetApp().StartPendingSave();
|
||||
m_PendingSaveFlag = true;
|
||||
}
|
||||
|
||||
CompressThread_gzip::CompressThread_gzip( const wxString& file, SafeArray<u8>* srcdata, FnType_WriteCompressedHeader* writeheader )
|
||||
: BaseCompressThread( file, srcdata, writeheader )
|
||||
{
|
||||
|
@ -35,6 +46,8 @@ CompressThread_gzip::CompressThread_gzip( const wxString& file, ScopedPtr< SafeA
|
|||
|
||||
CompressThread_gzip::~CompressThread_gzip() throw()
|
||||
{
|
||||
_parent::Cancel();
|
||||
|
||||
if( m_gzfp ) gzclose( m_gzfp );
|
||||
}
|
||||
|
||||
|
@ -46,11 +59,21 @@ void CompressThread_gzip::Write( const void* data, size_t size )
|
|||
|
||||
void CompressThread_gzip::ExecuteTaskInThread()
|
||||
{
|
||||
// TODO : Add an API to PersistentThread for this! :) --air
|
||||
//SetThreadPriority( THREAD_PRIORITY_BELOW_NORMAL );
|
||||
|
||||
if( !m_src_buffer ) return;
|
||||
|
||||
SetPendingSave();
|
||||
|
||||
Yield( 3 );
|
||||
|
||||
if( !(m_gzfp = gzopen(m_filename.ToUTF8(), "wb")) )
|
||||
// Safeguard against corruption by writing to a temp file, and then
|
||||
// copying the final result over the original:
|
||||
|
||||
wxString tempfile( m_filename + L".tmp" );
|
||||
|
||||
if( !(m_gzfp = gzopen(tempfile.ToUTF8(), "wb")) )
|
||||
throw Exception::CannotCreateStream( m_filename );
|
||||
|
||||
gzsetparams(m_gzfp, Z_BEST_SPEED, Z_FILTERED); // Best speed at good compression
|
||||
|
@ -67,14 +90,21 @@ void CompressThread_gzip::ExecuteTaskInThread()
|
|||
if( gzwrite( m_gzfp, m_src_buffer->GetPtr(curidx), thisBlockSize ) < thisBlockSize )
|
||||
throw Exception::BadStream( m_filename );
|
||||
curidx += thisBlockSize;
|
||||
Yield( 3 );
|
||||
Yield( 2 );
|
||||
} while( curidx < m_src_buffer->GetSizeInBytes() );
|
||||
|
||||
|
||||
gzclose( m_gzfp );
|
||||
m_gzfp = NULL;
|
||||
|
||||
if( !wxRenameFile( tempfile, m_filename, true ) )
|
||||
throw Exception::BadStream( m_filename, "Failed to move or copy the temporary archive to the destination filename." );
|
||||
|
||||
Console.WriteLn( "(gzipThread) Data saved to disk without error." );
|
||||
}
|
||||
|
||||
void CompressThread_gzip::OnCleanupInThread()
|
||||
{
|
||||
_parent::OnCleanupInThread();
|
||||
wxGetApp().DeleteThread( this );
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ enum MenuIdentifiers
|
|||
|
||||
// Config Subsection
|
||||
MenuId_Config_SysSettings,
|
||||
MenuId_Config_McdSettings,
|
||||
MenuId_Config_AppSettings,
|
||||
MenuId_Config_BIOS,
|
||||
|
||||
|
@ -635,7 +636,7 @@ DECLARE_APP(Pcsx2App)
|
|||
// AppOpenDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
template<typename DialogType>
|
||||
void AppOpenDialog( wxWindow* parent )
|
||||
void AppOpenDialog( wxWindow* parent=NULL )
|
||||
{
|
||||
if( wxWindow* window = wxFindWindowByName( DialogType::GetNameStatic() ) )
|
||||
window->SetFocus();
|
||||
|
@ -674,6 +675,9 @@ extern __aligned16 AppPluginManager CorePlugins;
|
|||
|
||||
extern void UI_UpdateSysControls();
|
||||
|
||||
extern void UI_DisableStateActions();
|
||||
extern void UI_EnableStateActions();
|
||||
|
||||
extern void UI_DisableSysActions();
|
||||
extern void UI_EnableSysActions();
|
||||
|
||||
|
|
|
@ -106,14 +106,13 @@ static wxString pxGetStackTrace( const FnChar_t* calledFrom )
|
|||
|
||||
#ifdef __WXDEBUG__
|
||||
|
||||
static TlsVariable< int > _reentrant_lock( 0 );
|
||||
|
||||
// This override of wx's implementation provides thread safe assertion message reporting. If we aren't
|
||||
// on the main gui thread then the assertion message box needs to be passed off to the main gui thread
|
||||
// via messages.
|
||||
// This override of wx's implementation provides thread safe assertion message reporting.
|
||||
// If we aren't on the main gui thread then the assertion message box needs to be passed
|
||||
// off to the main gui thread via messages.
|
||||
void Pcsx2App::OnAssertFailure( const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg )
|
||||
{
|
||||
// Re-entrant assertions are bad mojo -- trap immediately.
|
||||
static DeclareTls(int) _reentrant_lock( 0 );
|
||||
RecursionGuard guard( _reentrant_lock );
|
||||
if( guard.IsReentrant() ) wxTrap();
|
||||
|
||||
|
|
|
@ -344,6 +344,7 @@ wxString AppConfig::FullpathToMcd( uint port, uint slot ) const
|
|||
AppConfig::AppConfig()
|
||||
: MainGuiPosition( wxDefaultPosition )
|
||||
, SysSettingsTabName( L"Cpu" )
|
||||
, McdSettingsTabName( L"Standard" )
|
||||
, AppSettingsTabName( L"GS Window" )
|
||||
, DeskTheme( L"default" )
|
||||
{
|
||||
|
@ -353,7 +354,8 @@ AppConfig::AppConfig()
|
|||
Toolbar_ImageSize = 24;
|
||||
Toolbar_ShowLabels = true;
|
||||
|
||||
McdEnableNTFS = true;
|
||||
McdCompressNTFS = true;
|
||||
McdEnableEjection = true;
|
||||
EnableSpeedHacks = false;
|
||||
EnableGameFixes = false;
|
||||
|
||||
|
@ -423,6 +425,7 @@ void AppConfig::LoadSaveRootItems( IniInterface& ini )
|
|||
|
||||
IniEntry( MainGuiPosition );
|
||||
IniEntry( SysSettingsTabName );
|
||||
IniEntry( McdSettingsTabName );
|
||||
IniEntry( AppSettingsTabName );
|
||||
ini.EnumEntry( L"LanguageId", LanguageId, NULL, defaults.LanguageId );
|
||||
IniEntry( RecentIsoCount );
|
||||
|
@ -436,6 +439,9 @@ void AppConfig::LoadSaveRootItems( IniInterface& ini )
|
|||
|
||||
IniEntry( EnableSpeedHacks );
|
||||
IniEntry( EnableGameFixes );
|
||||
|
||||
IniEntry( McdCompressNTFS );
|
||||
IniEntry( McdEnableEjection );
|
||||
|
||||
ini.EnumEntry( L"CdvdSource", CdvdSource, CDVD_SourceLabels, defaults.CdvdSource );
|
||||
}
|
||||
|
|
|
@ -182,6 +182,7 @@ public:
|
|||
// Because remembering the last used tab on the settings panel is cool (tab is remembered
|
||||
// by it's UTF/ASCII name).
|
||||
wxString SysSettingsTabName;
|
||||
wxString McdSettingsTabName;
|
||||
wxString AppSettingsTabName;
|
||||
|
||||
// Current language in use (correlates to a wxWidgets wxLANGUAGE specifier)
|
||||
|
@ -204,8 +205,13 @@ public:
|
|||
// Enables display of toolbar text labels.
|
||||
bool Toolbar_ShowLabels;
|
||||
|
||||
// enables automatic ntfs compression of memory cards (Win32 only)
|
||||
bool McdEnableNTFS;
|
||||
#ifdef __WXMSW__
|
||||
// uses automatic ntfs compression when creating new memory cards (Win32 only)
|
||||
bool McdCompressNTFS;
|
||||
#endif
|
||||
|
||||
// Force-ejects modified memory cards when loading savestates (avoids corruption)
|
||||
bool McdEnableEjection;
|
||||
|
||||
// Master toggle for enabling or disabling all speedhacks in one fail-free swoop.
|
||||
// (the toggle is applied when a new EmuConfig is sent through AppCoreThread::ApplySettings)
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
PluginEventType GetEventType() { return m_evt; }
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
sApp.DispatchEvent( m_evt );
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
if( m_method ) (CorePlugins.*m_method)();
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
CorePlugins.Load( m_folders );
|
||||
}
|
||||
|
@ -337,13 +337,15 @@ void ScopedCoreThreadClose::LoadPlugins()
|
|||
class SysExecEvent_UnloadPlugins : public SysExecEvent
|
||||
{
|
||||
public:
|
||||
wxString GetEventName() const { return L"UnloadPlugins"; }
|
||||
|
||||
virtual ~SysExecEvent_UnloadPlugins() throw() {}
|
||||
SysExecEvent_UnloadPlugins* Clone() const { return new SysExecEvent_UnloadPlugins(*this); }
|
||||
|
||||
virtual bool AllowCancelOnExit() const { return false; }
|
||||
virtual bool IsCriticalEvent() const { return true; }
|
||||
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
CoreThread.Cancel();
|
||||
CorePlugins.Unload();
|
||||
|
@ -353,13 +355,15 @@ public:
|
|||
class SysExecEvent_ShutdownPlugins : public SysExecEvent
|
||||
{
|
||||
public:
|
||||
wxString GetEventName() const { return L"ShutdownPlugins"; }
|
||||
|
||||
virtual ~SysExecEvent_ShutdownPlugins() throw() {}
|
||||
SysExecEvent_ShutdownPlugins* Clone() const { return new SysExecEvent_ShutdownPlugins(*this); }
|
||||
|
||||
virtual bool AllowCancelOnExit() const { return false; }
|
||||
virtual bool IsCriticalEvent() const { return true; }
|
||||
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
CoreThread.Cancel();
|
||||
CorePlugins.Shutdown();
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "App.h"
|
||||
#include "AppSaveStates.h"
|
||||
|
||||
#include "Utilities/TlsVariable.inl"
|
||||
|
||||
#include "ps2/BiosTools.h"
|
||||
#include "GS.h"
|
||||
|
||||
|
@ -78,7 +80,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
if( m_method ) (CoreThread.*m_method)();
|
||||
}
|
||||
|
@ -99,7 +101,7 @@ static void _Suspend()
|
|||
|
||||
void AppCoreThread::Suspend( bool isBlocking )
|
||||
{
|
||||
if( !GetSysExecutorThread().SelfProcessMethod( _Suspend ) )
|
||||
if( !GetSysExecutorThread().ProcessMethodSelf( _Suspend ) )
|
||||
_parent::Suspend(true);
|
||||
}
|
||||
|
||||
|
@ -107,7 +109,13 @@ static int resume_tries = 0;
|
|||
|
||||
void AppCoreThread::Resume()
|
||||
{
|
||||
if( !AffinityAssert_AllowFrom_SysExecutor() ) return;
|
||||
//if( !AffinityAssert_AllowFrom_SysExecutor() ) return;
|
||||
if( !GetSysExecutorThread().IsSelf() )
|
||||
{
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_InvokeCoreThreadMethod(&AppCoreThread::Resume) );
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_ExecMode == ExecMode_Opened || (m_CloseTemporary > 0) ) return;
|
||||
|
||||
if( !pxAssert( CorePlugins.AreLoaded() ) ) return;
|
||||
|
@ -327,25 +335,27 @@ protected:
|
|||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_FullStop
|
||||
// SysExecEvent_CoreThreadClose
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_FullStop : public BaseSysExecEvent_ScopedCore
|
||||
class SysExecEvent_CoreThreadClose : public BaseSysExecEvent_ScopedCore
|
||||
{
|
||||
public:
|
||||
virtual ~SysExecEvent_FullStop() throw() {}
|
||||
SysExecEvent_FullStop* Clone() const
|
||||
wxString GetEventName() const { return L"CloseCoreThread"; }
|
||||
|
||||
virtual ~SysExecEvent_CoreThreadClose() throw() {}
|
||||
SysExecEvent_CoreThreadClose* Clone() const
|
||||
{
|
||||
return new SysExecEvent_FullStop( *this );
|
||||
return new SysExecEvent_CoreThreadClose( *this );
|
||||
}
|
||||
|
||||
SysExecEvent_FullStop( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
SysExecEvent_CoreThreadClose( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: BaseSysExecEvent_ScopedCore( sync, resume_sync, mtx_resume ) { }
|
||||
|
||||
SysExecEvent_FullStop( SynchronousActionState& sync, SynchronousActionState& resume_sync, Threading::Mutex& mtx_resume )
|
||||
SysExecEvent_CoreThreadClose( SynchronousActionState& sync, SynchronousActionState& resume_sync, Threading::Mutex& mtx_resume )
|
||||
: BaseSysExecEvent_ScopedCore( &sync, &resume_sync, &mtx_resume ) { }
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
ScopedCoreThreadClose closed_core;
|
||||
_post_and_wait(closed_core);
|
||||
|
@ -354,25 +364,27 @@ protected:
|
|||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_FullStop
|
||||
// SysExecEvent_CoreThreadPause
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_Pause : public BaseSysExecEvent_ScopedCore
|
||||
class SysExecEvent_CoreThreadPause : public BaseSysExecEvent_ScopedCore
|
||||
{
|
||||
public:
|
||||
virtual ~SysExecEvent_Pause() throw() {}
|
||||
SysExecEvent_Pause* Clone() const
|
||||
wxString GetEventName() const { return L"PauseCoreThread"; }
|
||||
|
||||
virtual ~SysExecEvent_CoreThreadPause() throw() {}
|
||||
SysExecEvent_CoreThreadPause* Clone() const
|
||||
{
|
||||
return new SysExecEvent_Pause( *this );
|
||||
return new SysExecEvent_CoreThreadPause( *this );
|
||||
}
|
||||
|
||||
SysExecEvent_Pause( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
SysExecEvent_CoreThreadPause( SynchronousActionState* sync=NULL, SynchronousActionState* resume_sync=NULL, Threading::Mutex* mtx_resume=NULL )
|
||||
: BaseSysExecEvent_ScopedCore( sync, resume_sync, mtx_resume ) { }
|
||||
|
||||
SysExecEvent_Pause( SynchronousActionState& sync, SynchronousActionState& resume_sync, Threading::Mutex& mtx_resume )
|
||||
SysExecEvent_CoreThreadPause( SynchronousActionState& sync, SynchronousActionState& resume_sync, Threading::Mutex& mtx_resume )
|
||||
: BaseSysExecEvent_ScopedCore( &sync, &resume_sync, &mtx_resume ) { }
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
ScopedCoreThreadPause paused_core;
|
||||
_post_and_wait(paused_core);
|
||||
|
@ -384,8 +396,8 @@ protected:
|
|||
// ScopedCoreThreadClose / ScopedCoreThreadPause
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
static __threadlocal bool ScopedCore_IsPaused = false;
|
||||
static __threadlocal bool ScopedCore_IsFullyClosed = false;
|
||||
static DeclareTls(bool) ScopedCore_IsPaused = false;
|
||||
static DeclareTls(bool) ScopedCore_IsFullyClosed = false;
|
||||
|
||||
BaseScopedCoreThread::BaseScopedCoreThread()
|
||||
{
|
||||
|
@ -440,7 +452,7 @@ ScopedCoreThreadClose::ScopedCoreThreadClose()
|
|||
{
|
||||
//DbgCon.WriteLn("(ScopedCoreThreadClose) Threaded Scope Created!");
|
||||
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_FullStop(m_sync, m_sync_resume, m_mtx_resume) );
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_CoreThreadClose(m_sync, m_sync_resume, m_mtx_resume) );
|
||||
m_sync.WaitForResult();
|
||||
m_sync.RethrowException();
|
||||
}
|
||||
|
@ -470,7 +482,7 @@ ScopedCoreThreadPause::ScopedCoreThreadPause()
|
|||
{
|
||||
//DbgCon.WriteLn("(ScopedCoreThreadPause) Threaded Scope Created!");
|
||||
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_Pause(m_sync, m_sync_resume, m_mtx_resume) );
|
||||
GetSysExecutorThread().PostEvent( SysExecEvent_CoreThreadPause(m_sync, m_sync_resume, m_mtx_resume) );
|
||||
m_sync.WaitForResult();
|
||||
m_sync.RethrowException();
|
||||
}
|
||||
|
|
|
@ -266,5 +266,5 @@ public:
|
|||
CoreThreadStatus GetEventType() { return m_evt; }
|
||||
|
||||
protected:
|
||||
void _DoInvoke();
|
||||
void InvokeEvent();
|
||||
};
|
||||
|
|
|
@ -168,7 +168,7 @@ CoreThreadStatusEvent::CoreThreadStatusEvent( CoreThreadStatus evt, SynchronousA
|
|||
m_evt = evt;
|
||||
}
|
||||
|
||||
void CoreThreadStatusEvent::_DoInvoke()
|
||||
void CoreThreadStatusEvent::InvokeEvent()
|
||||
{
|
||||
sApp.DispatchEvent( m_evt );
|
||||
}
|
||||
|
|
|
@ -562,7 +562,7 @@ public:
|
|||
protected:
|
||||
// When the SysExec message queue is finally empty, we should check the state of
|
||||
// the menus and make sure they're all consistent to the current emulation states.
|
||||
void DoIdle()
|
||||
void _DoIdle()
|
||||
{
|
||||
UI_UpdateSysControls();
|
||||
}
|
||||
|
|
|
@ -47,94 +47,106 @@ bool UseDefaultSettingsFolder = true;
|
|||
ScopedPtr<AppConfig> g_Conf;
|
||||
ConfigOverrides OverrideOptions;
|
||||
|
||||
class NamedDialogBoxEvent : public BaseMessageBoxEvent
|
||||
template<typename DialogType>
|
||||
int AppOpenModalDialog( wxWindow* parent=NULL )
|
||||
{
|
||||
typedef BaseMessageBoxEvent _parent;
|
||||
DECLARE_DYNAMIC_CLASS_NO_ASSIGN(NamedDialogBoxEvent)
|
||||
|
||||
public:
|
||||
virtual ~NamedDialogBoxEvent() throw() { }
|
||||
virtual NamedDialogBoxEvent *Clone() const { return new NamedDialogBoxEvent(*this); }
|
||||
|
||||
NamedDialogBoxEvent() {}
|
||||
NamedDialogBoxEvent( const wxString& name, SynchronousActionState& sync )
|
||||
: BaseMessageBoxEvent( name, sync ) {}
|
||||
NamedDialogBoxEvent( const wxString& name, SynchronousActionState* sync=NULL )
|
||||
: BaseMessageBoxEvent( name, sync ) {}
|
||||
|
||||
protected:
|
||||
int _DoDialog() const
|
||||
if( wxWindow* window = wxFindWindowByName( DialogType::GetNameStatic() ) )
|
||||
{
|
||||
const wxString& dlgName( m_Content );
|
||||
|
||||
if( dlgName.IsEmpty() ) return wxID_CANCEL;
|
||||
|
||||
if( wxWindow* window = wxFindWindowByName( dlgName ) )
|
||||
window->SetFocus();
|
||||
if( wxDialog* dialog = wxDynamicCast( window, wxDialog ) )
|
||||
{
|
||||
if( wxDialog* dialog = wxDynamicCast( window, wxDialog ) )
|
||||
// It's legal to call ShowModal on a non-modal dialog, therefore making
|
||||
// it modal in nature for the needs of whatever other thread of action wants
|
||||
// to block against it:
|
||||
|
||||
if( !dialog->IsModal() )
|
||||
{
|
||||
window->SetFocus();
|
||||
|
||||
// It's legal to call ShowModal on a non-modal dialog, therefore making
|
||||
// it modal in nature for the needs of whatever other thread of action wants
|
||||
// to block against it:
|
||||
|
||||
if( !dialog->IsModal() )
|
||||
{
|
||||
int result = dialog->ShowModal();
|
||||
dialog->Destroy();
|
||||
return result;
|
||||
}
|
||||
int result = dialog->ShowModal();
|
||||
dialog->Destroy();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using namespace Dialogs;
|
||||
|
||||
if( dlgName == SysConfigDialog::GetNameStatic() )
|
||||
return SysConfigDialog().ShowModal();
|
||||
if( dlgName == AppConfigDialog::GetNameStatic() )
|
||||
return AppConfigDialog().ShowModal();
|
||||
if( dlgName == BiosSelectorDialog::GetNameStatic() )
|
||||
return BiosSelectorDialog().ShowModal();
|
||||
if( dlgName == LogOptionsDialog::GetNameStatic() )
|
||||
return LogOptionsDialog().ShowModal();
|
||||
if( dlgName == AboutBoxDialog::GetNameStatic() )
|
||||
return AboutBoxDialog().ShowModal();
|
||||
}
|
||||
|
||||
pxFailDev( "Can only show wxDialog class windows as modal!" );
|
||||
return wxID_CANCEL;
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS( NamedDialogBoxEvent, BaseMessageBoxEvent );
|
||||
|
||||
// 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
|
||||
static int IssueDialogAsModal( const wxString& dlgName )
|
||||
{
|
||||
BaseMessageBoxEvent tevt( dlgName );
|
||||
return Msgbox::ShowModal( tevt );
|
||||
else
|
||||
return DialogType( parent ).ShowModal();
|
||||
}
|
||||
|
||||
static bool HandlePluginError( Exception::PluginError& ex )
|
||||
static bool HandlePluginError( Exception::BaseException& ex )
|
||||
{
|
||||
if( pxDialogExists( L"CoreSettings" ) ) return true;
|
||||
|
||||
bool result = Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||
_("\n\nPress Ok to go to the Plugin Configuration Panel.")
|
||||
);
|
||||
|
||||
if( result )
|
||||
if( !pxDialogExists( L"CoreSettings" ) )
|
||||
{
|
||||
g_Conf->SysSettingsTabName = L"Plugins";
|
||||
|
||||
// fixme: Send a message to the panel to select the failed plugin.
|
||||
if( IssueDialogAsModal( Dialogs::SysConfigDialog::GetNameStatic() ) == wxID_CANCEL )
|
||||
return false;
|
||||
if( !Msgbox::OkCancel( ex.FormatDisplayMessage() +
|
||||
_("\n\nPress Ok to go to the Plugin Configuration Panel.")
|
||||
) )
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Conf->SysSettingsTabName = L"Plugins";
|
||||
|
||||
// TODO: Send a message to the panel to select the failed plugin.
|
||||
|
||||
return AppOpenModalDialog<Dialogs::SysConfigDialog>() != wxID_CANCEL;
|
||||
}
|
||||
|
||||
class PluginErrorEvent : public pxExceptionEvent
|
||||
{
|
||||
typedef pxExceptionEvent _parent;
|
||||
|
||||
public:
|
||||
PluginErrorEvent( BaseException* ex=NULL ) : _parent( ex ) {}
|
||||
PluginErrorEvent( const BaseException& ex ) : _parent( ex ) {}
|
||||
|
||||
virtual ~PluginErrorEvent() throw() { }
|
||||
virtual PluginErrorEvent *Clone() const { return new PluginErrorEvent(*this); }
|
||||
|
||||
protected:
|
||||
void InvokeEvent();
|
||||
};
|
||||
|
||||
class PluginInitErrorEvent : public pxExceptionEvent
|
||||
{
|
||||
typedef pxExceptionEvent _parent;
|
||||
|
||||
public:
|
||||
PluginInitErrorEvent( BaseException* ex=NULL ) : _parent( ex ) {}
|
||||
PluginInitErrorEvent( const BaseException& ex ) : _parent( ex ) {}
|
||||
|
||||
virtual ~PluginInitErrorEvent() throw() { }
|
||||
virtual PluginInitErrorEvent *Clone() const { return new PluginInitErrorEvent(*this); }
|
||||
|
||||
protected:
|
||||
void InvokeEvent();
|
||||
|
||||
};
|
||||
|
||||
void PluginErrorEvent::InvokeEvent()
|
||||
{
|
||||
if( !m_except ) return;
|
||||
|
||||
ScopedPtr<BaseException> deleteMe( m_except );
|
||||
m_except = NULL;
|
||||
|
||||
if( !HandlePluginError( *deleteMe ) )
|
||||
{
|
||||
Console.Error( L"User-canceled plugin configuration; Plugins not loaded!" );
|
||||
Msgbox::Alert( _("Warning! System plugins have not been loaded. PCSX2 may be inoperable.") );
|
||||
}
|
||||
}
|
||||
|
||||
void PluginInitErrorEvent::InvokeEvent()
|
||||
{
|
||||
if( !m_except ) return;
|
||||
|
||||
ScopedPtr<BaseException> deleteMe( m_except );
|
||||
m_except = NULL;
|
||||
|
||||
if( !HandlePluginError( *deleteMe ) )
|
||||
{
|
||||
Console.Error( L"User-canceled plugin configuration after plugin initialization failure. Plugins unloaded." );
|
||||
Msgbox::Alert( _("Warning! System plugins have not been loaded. PCSX2 may be inoperable.") );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Allows for activating menu actions from anywhere in PCSX2.
|
||||
|
@ -194,7 +206,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
if( m_Method ) (wxGetApp().*m_Method)();
|
||||
}
|
||||
|
@ -324,25 +336,6 @@ void Pcsx2App::LogicalVsync()
|
|||
// Pcsx2App Event Handlers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*int 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 );
|
||||
}*/
|
||||
|
||||
|
||||
HashTools::HashMap<int, const GlobalCommandDescriptor*> GlobalAccels( 0, 0xffffffff );
|
||||
|
||||
void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt )
|
||||
|
@ -403,10 +396,8 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
if( dialog.ShowModal() == wxID_CANCEL )
|
||||
Console.Warning( "User denied option to re-configure BIOS." );
|
||||
|
||||
if( IssueDialogAsModal( Dialogs::BiosSelectorDialog::GetNameStatic() ) != wxID_CANCEL )
|
||||
{
|
||||
if( AppOpenModalDialog<Dialogs::BiosSelectorDialog>() != wxID_CANCEL )
|
||||
SysExecute();
|
||||
}
|
||||
else
|
||||
Console.Warning( "User canceled BIOS configuration." );
|
||||
}
|
||||
|
@ -418,27 +409,20 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
StateCopy_Clear();
|
||||
CoreThread.Resume();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
catch( Exception::PluginInitError& ex )
|
||||
{
|
||||
CorePlugins.Shutdown();
|
||||
ShutdownPlugins();
|
||||
|
||||
Console.Error( ex.FormatDiagnosticMessage() );
|
||||
if( !HandlePluginError( ex ) )
|
||||
{
|
||||
Console.Error( L"User-canceled plugin configuration after plugin initialization failure. Plugins unloaded." );
|
||||
Msgbox::Alert( _("Warning! System plugins have not been loaded. PCSX2 may be inoperable.") );
|
||||
}
|
||||
AddIdleEvent( PluginInitErrorEvent(ex) );
|
||||
}
|
||||
catch( Exception::PluginError& ex )
|
||||
{
|
||||
CorePlugins.Close();
|
||||
UnloadPlugins();
|
||||
|
||||
Console.Error( ex.FormatDiagnosticMessage() );
|
||||
if( !HandlePluginError( ex ) )
|
||||
{
|
||||
Console.Error( L"User-canceled plugin configuration; Plugins not loaded!" );
|
||||
Msgbox::Alert( _("Warning! System plugins have not been loaded. PCSX2 may be inoperable.") );
|
||||
}
|
||||
AddIdleEvent( PluginErrorEvent(ex) );
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
#if 0
|
||||
|
@ -501,7 +485,7 @@ void Pcsx2App::StartPendingSave()
|
|||
|
||||
void Pcsx2App::ClearPendingSave()
|
||||
{
|
||||
if( PostAppMethodMyself(&Pcsx2App::StartPendingSave) ) return;
|
||||
if( PostAppMethodMyself(&Pcsx2App::ClearPendingSave) ) return;
|
||||
|
||||
--m_PendingSaves;
|
||||
pxAssumeDev( m_PendingSaves >= 0, "Pending saves count mismatch (pending count is less than 0)" );
|
||||
|
@ -529,8 +513,13 @@ void Pcsx2App::PrepForExit()
|
|||
|
||||
if( m_PendingSaves != 0 )
|
||||
{
|
||||
// When the thread finishes, it will call ClearPendingSave, which in turn will
|
||||
// exit the app once all pending saves have "logged out." (if one does not track
|
||||
// itself using our PendingSaves feature, it would be lost -- too bad!)
|
||||
|
||||
Console.WriteLn( "App: Saves are pending; exit postponed..." );
|
||||
sApp.SetExitOnFrameDelete( false );
|
||||
SetExitOnFrameDelete( false );
|
||||
m_ScheduledTermination = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -600,7 +589,7 @@ void AppApplySettings( const AppConfig* oldconf )
|
|||
// Update the compression attribute on the Memcards folder.
|
||||
// Memcards generally compress very well via NTFS compression.
|
||||
|
||||
NTFS_CompressFile( g_Conf->Folders.MemoryCards.ToString(), g_Conf->McdEnableNTFS );
|
||||
NTFS_CompressFile( g_Conf->Folders.MemoryCards.ToString(), g_Conf->McdCompressNTFS );
|
||||
sApp.DispatchEvent( AppStatus_SettingsApplied );
|
||||
|
||||
paused_core.AllowResume();
|
||||
|
@ -838,9 +827,9 @@ void Pcsx2App::OnMainFrameClosed( wxWindowID id )
|
|||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecuteEvent
|
||||
// SysExecEvent_Execute
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecuteEvent : public SysExecEvent
|
||||
class SysExecEvent_Execute : public SysExecEvent
|
||||
{
|
||||
protected:
|
||||
bool m_UseCDVDsrc;
|
||||
|
@ -849,8 +838,8 @@ protected:
|
|||
wxString m_elf_override;
|
||||
|
||||
public:
|
||||
virtual ~SysExecuteEvent() throw() {}
|
||||
SysExecuteEvent* Clone() const { return new SysExecuteEvent(*this); }
|
||||
virtual ~SysExecEvent_Execute() throw() {}
|
||||
SysExecEvent_Execute* Clone() const { return new SysExecEvent_Execute(*this); }
|
||||
|
||||
wxString GetEventName() const
|
||||
{
|
||||
|
@ -862,13 +851,13 @@ public:
|
|||
return _("Executing PS2 Virtual Machine...");
|
||||
}
|
||||
|
||||
SysExecuteEvent()
|
||||
SysExecEvent_Execute()
|
||||
: m_UseCDVDsrc(false)
|
||||
, m_UseELFOverride(false)
|
||||
{
|
||||
}
|
||||
|
||||
SysExecuteEvent( CDVD_SourceType srctype, const wxString& elf_override )
|
||||
SysExecEvent_Execute( CDVD_SourceType srctype, const wxString& elf_override )
|
||||
: m_UseCDVDsrc(true)
|
||||
, m_UseELFOverride(true)
|
||||
, m_cdvdsrc_type(srctype)
|
||||
|
@ -877,7 +866,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
wxGetApp().ProcessMethod( AppSaveSettings );
|
||||
|
||||
|
@ -905,7 +894,7 @@ protected:
|
|||
// configured CDVD source device.
|
||||
void Pcsx2App::SysExecute()
|
||||
{
|
||||
SysExecutorThread.PostEvent( new SysExecuteEvent() );
|
||||
SysExecutorThread.PostEvent( new SysExecEvent_Execute() );
|
||||
}
|
||||
|
||||
// Executes the specified cdvd source and optional elf file. This command performs a
|
||||
|
@ -913,7 +902,7 @@ void Pcsx2App::SysExecute()
|
|||
// sources.
|
||||
void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override )
|
||||
{
|
||||
SysExecutorThread.PostEvent( new SysExecuteEvent(cdvdsrc, elf_override) );
|
||||
SysExecutorThread.PostEvent( new SysExecEvent_Execute(cdvdsrc, elf_override) );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -933,7 +922,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
StateCopy_Clear();
|
||||
CoreThread.Shutdown();
|
||||
|
|
|
@ -151,7 +151,7 @@ ConsoleLogFrame::ColorArray::ColorArray( int fontsize ) :
|
|||
Create( fontsize );
|
||||
}
|
||||
|
||||
ConsoleLogFrame::ColorArray::~ColorArray()
|
||||
ConsoleLogFrame::ColorArray::~ColorArray() throw()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
@ -351,7 +351,7 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
|
|||
{
|
||||
pthread_testcancel();
|
||||
|
||||
ScopedLock lock( m_QueueLock );
|
||||
ScopedLock lock( m_mtx_Queue );
|
||||
|
||||
if( m_QueueColorSection.GetLength() == 0 )
|
||||
{
|
||||
|
@ -378,10 +378,22 @@ void ConsoleLogFrame::Write( ConsoleColors color, const wxString& text )
|
|||
|
||||
if( !m_pendingFlushMsg )
|
||||
{
|
||||
m_pendingFlushMsg = true;
|
||||
|
||||
// wxWidgets may have aggressive locks on event processing, so best to release
|
||||
// our own mutex lest wx get hung for an extended period of time and cause all
|
||||
// of our own stuff to get sluggish.
|
||||
lock.Release();
|
||||
|
||||
wxCommandEvent evt( pxEvt_FlushQueue );
|
||||
evt.SetInt( 0 );
|
||||
GetEventHandler()->AddPendingEvent( evt );
|
||||
m_pendingFlushMsg = true;
|
||||
if( wxThread::IsMain() )
|
||||
GetEventHandler()->ProcessEvent( evt );
|
||||
else
|
||||
{
|
||||
GetEventHandler()->AddPendingEvent( evt );
|
||||
}
|
||||
lock.Acquire();
|
||||
}
|
||||
|
||||
++m_pendingFlushes;
|
||||
|
@ -624,7 +636,7 @@ void ConsoleLogFrame::OnFlushLimiterTimer( wxTimerEvent& )
|
|||
|
||||
void ConsoleLogFrame::OnFlushEvent( wxCommandEvent& )
|
||||
{
|
||||
ScopedLock locker( m_QueueLock );
|
||||
ScopedLock locker( m_mtx_Queue );
|
||||
m_pendingFlushMsg = false;
|
||||
|
||||
// recursion guard needed due to Mutex lock/acquire code below, which can end up yielding
|
||||
|
|
|
@ -144,7 +144,7 @@ protected:
|
|||
wxTextAttr m_color_default;
|
||||
|
||||
public:
|
||||
virtual ~ColorArray();
|
||||
virtual ~ColorArray() throw();
|
||||
ColorArray( int fontsize=8 );
|
||||
|
||||
void Create( int fontsize );
|
||||
|
@ -217,7 +217,7 @@ protected:
|
|||
|
||||
// Lock object for accessing or modifying the following three vars:
|
||||
// m_QueueBuffer, m_QueueColorSelection, m_CurQueuePos
|
||||
MutexRecursive m_QueueLock;
|
||||
MutexRecursive m_mtx_Queue;
|
||||
|
||||
// Describes a series of colored text sections in the m_QueueBuffer.
|
||||
SafeList<ColorSection> m_QueueColorSection;
|
||||
|
|
|
@ -56,7 +56,7 @@ Dialogs::BaseApplicableDialog::~BaseApplicableDialog() throw()
|
|||
}
|
||||
|
||||
Dialogs::BaseConfigurationDialog::BaseConfigurationDialog( wxWindow* parent, const wxString& title, wxImageList& bookicons, int idealWidth )
|
||||
: BaseApplicableDialog( parent, title, wxVERTICAL )
|
||||
: _parent( parent, title, wxVERTICAL )
|
||||
, m_listbook( *new wxListbook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, s_orient ) )
|
||||
{
|
||||
m_idealWidth = idealWidth;
|
||||
|
@ -64,13 +64,7 @@ Dialogs::BaseConfigurationDialog::BaseConfigurationDialog( wxWindow* parent, con
|
|||
m_listbook.SetImageList( &bookicons );
|
||||
m_ApplyState.StartBook( &m_listbook );
|
||||
|
||||
wxBitmapButton& screenshotButton( *new wxBitmapButton( this, wxID_SAVE, EmbeddedImage<res_ButtonIcon_Camera>().Get() ) );
|
||||
screenshotButton.SetToolTip( _("Saves a snapshot of this settings panel to a PNG file.") );
|
||||
|
||||
*this += m_listbook;
|
||||
AddOkCancel( *GetSizer(), true );
|
||||
|
||||
*m_extraButtonSizer += screenshotButton;
|
||||
*this += m_listbook | pxExpand.Border( wxLEFT | wxRIGHT, 2 );
|
||||
|
||||
Connect( wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BaseConfigurationDialog::OnOk_Click ) );
|
||||
Connect( wxID_CANCEL, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BaseConfigurationDialog::OnCancel_Click ) );
|
||||
|
@ -98,8 +92,17 @@ Dialogs::BaseConfigurationDialog::BaseConfigurationDialog( wxWindow* parent, con
|
|||
ConnectSomethingChanged( SPINCTRL_UPDATED );
|
||||
ConnectSomethingChanged( SLIDER_UPDATED );
|
||||
ConnectSomethingChanged( DIRPICKER_CHANGED );
|
||||
}
|
||||
|
||||
void Dialogs::BaseConfigurationDialog::AddOkCancel( wxSizer* sizer )
|
||||
{
|
||||
_parent::AddOkCancel( sizer, true );
|
||||
FindWindow( wxID_APPLY )->Disable();
|
||||
|
||||
wxBitmapButton& screenshotButton( *new wxBitmapButton( this, wxID_SAVE, EmbeddedImage<res_ButtonIcon_Camera>().Get() ) );
|
||||
screenshotButton.SetToolTip( _("Saves a snapshot of this settings panel to a PNG file.") );
|
||||
|
||||
*m_extraButtonSizer += screenshotButton;
|
||||
}
|
||||
|
||||
Dialogs::BaseConfigurationDialog::~BaseConfigurationDialog() throw()
|
||||
|
@ -112,7 +115,7 @@ void Dialogs::BaseConfigurationDialog::OnSomethingChanged( wxCommandEvent& evt )
|
|||
evt.Skip();
|
||||
if( (evt.GetId() != wxID_OK) && (evt.GetId() != wxID_CANCEL) && (evt.GetId() != wxID_APPLY) )
|
||||
{
|
||||
FindWindow( wxID_APPLY )->Enable();
|
||||
if( wxWindow *apply = FindWindow( wxID_APPLY ) ) apply->Enable();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,8 @@ namespace Dialogs
|
|||
// --------------------------------------------------------------------------------------
|
||||
class BaseConfigurationDialog : public BaseApplicableDialog
|
||||
{
|
||||
typedef BaseApplicableDialog _parent;
|
||||
|
||||
protected:
|
||||
wxListbook& m_listbook;
|
||||
wxArrayString m_labels;
|
||||
|
@ -53,10 +55,13 @@ namespace Dialogs
|
|||
virtual ~BaseConfigurationDialog() throw();
|
||||
BaseConfigurationDialog(wxWindow* parent, const wxString& title, wxImageList& bookicons, int idealWidth);
|
||||
|
||||
protected:
|
||||
public:
|
||||
void AddOkCancel( wxSizer* sizer=NULL );
|
||||
|
||||
template< typename T >
|
||||
void AddPage( const char* label, int iconid );
|
||||
|
||||
protected:
|
||||
void OnOk_Click( wxCommandEvent& evt );
|
||||
void OnCancel_Click( wxCommandEvent& evt );
|
||||
void OnApply_Click( wxCommandEvent& evt );
|
||||
|
@ -72,8 +77,6 @@ namespace Dialogs
|
|||
// --------------------------------------------------------------------------------------
|
||||
class SysConfigDialog : public BaseConfigurationDialog
|
||||
{
|
||||
protected:
|
||||
|
||||
public:
|
||||
virtual ~SysConfigDialog() throw() {}
|
||||
SysConfigDialog(wxWindow* parent=NULL);
|
||||
|
@ -83,6 +86,20 @@ namespace Dialogs
|
|||
virtual wxString& GetConfSettingsTabName() const { return g_Conf->SysSettingsTabName; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// McdConfigDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
class McdConfigDialog : public BaseConfigurationDialog
|
||||
{
|
||||
public:
|
||||
virtual ~McdConfigDialog() throw() {}
|
||||
McdConfigDialog(wxWindow* parent=NULL);
|
||||
static const wxChar* GetNameStatic() { return L"Dialog:MemoryCardSettings"; }
|
||||
|
||||
protected:
|
||||
virtual wxString& GetConfSettingsTabName() const { return g_Conf->McdSettingsTabName; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// AppConfigDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
extern wxString GetMsg_McdNtfsCompress();
|
||||
|
||||
wxFilePickerCtrl* CreateMemoryCardFilePicker( wxWindow* parent, uint portidx, uint slotidx, const wxString& filename=wxEmptyString )
|
||||
{
|
||||
return new wxFilePickerCtrl( parent, wxID_ANY, filename,
|
||||
|
@ -47,10 +49,7 @@ Dialogs::CreateMemoryCardDialog::CreateMemoryCardDialog( wxWindow* parent, uint
|
|||
#ifdef __WXMSW__
|
||||
m_check_CompressNTFS = new pxCheckBox( this,
|
||||
_("Use NTFS compression on this card"),
|
||||
pxE( ".Dialog:Memorycards:NtfsCompress",
|
||||
L"NTFS compression is built-in, fast, and completely reliable. Memorycards typically compress "
|
||||
L"very well, and run faster as a result, so this option is highly recommended."
|
||||
)
|
||||
GetMsg_McdNtfsCompress()
|
||||
);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/* 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 "ConfigurationDialog.h"
|
||||
#include "BaseConfigurationDialog.inl"
|
||||
#include "ModalPopups.h"
|
||||
#include "MSWstuff.h"
|
||||
|
||||
#include "Panels/ConfigurationPanels.h"
|
||||
#include "Panels/MemoryCardPanels.h"
|
||||
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
namespace Panels
|
||||
{
|
||||
// Helper class since the 'AddPage' template system needs a single-parameter constructor.
|
||||
class McdConfigPanel_Multitap2 : public McdConfigPanel_Multitap
|
||||
{
|
||||
public:
|
||||
McdConfigPanel_Multitap2( wxWindow* parent ) : McdConfigPanel_Multitap( parent, 1 ) {}
|
||||
virtual ~McdConfigPanel_Multitap2() throw() { }
|
||||
};
|
||||
}
|
||||
|
||||
wxString GetMsg_McdNtfsCompress()
|
||||
{
|
||||
return pxE( ".Dialog:Memorycards:NtfsCompress",
|
||||
L"NTFS compression is built-in, fast, and completely reliable; and typically compresses MemoryCards "
|
||||
L"very well (this option is highly recommended)."
|
||||
);
|
||||
}
|
||||
|
||||
Panels::McdConfigPanel_Toggles::McdConfigPanel_Toggles(wxWindow *parent)
|
||||
: _parent( parent )
|
||||
{
|
||||
m_idealWidth -= 48;
|
||||
|
||||
m_check_Ejection = new pxCheckBox( this,
|
||||
_("Auto-eject memorycards when loading savestates"),
|
||||
pxE( ".Dialog:Memorycards:EnableEjection",
|
||||
L"Avoids memorycard corruption by forcing games to re-index card contents after "
|
||||
L"loading from savestates. May not be compatible with all games (Guitar Hero)."
|
||||
)
|
||||
);
|
||||
|
||||
#ifdef __WXMSW__
|
||||
m_check_CompressNTFS = new pxCheckBox( this,
|
||||
_("Enable NTFS Compression on all cards by default."),
|
||||
GetMsg_McdNtfsCompress()
|
||||
);
|
||||
#endif
|
||||
|
||||
*this += m_check_Ejection | pxExpand;
|
||||
*this += m_check_CompressNTFS | pxExpand;
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Toggles::Apply()
|
||||
{
|
||||
g_Conf->McdEnableEjection = m_check_Ejection->GetValue();
|
||||
g_Conf->McdCompressNTFS = m_check_CompressNTFS->GetValue();
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Toggles::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_check_Ejection ->SetValue( g_Conf->McdEnableEjection );
|
||||
m_check_CompressNTFS ->SetValue( g_Conf->McdCompressNTFS );
|
||||
}
|
||||
|
||||
Panels::McdConfigPanel_Standard::McdConfigPanel_Standard(wxWindow *parent) : _parent( parent )
|
||||
{
|
||||
m_panel_cardinfo[0] = new MemoryCardInfoPanel( this, 0, 0 );
|
||||
m_panel_cardinfo[1] = new MemoryCardInfoPanel( this, 1, 0 );
|
||||
|
||||
for( uint port=0; port<2; ++port )
|
||||
{
|
||||
wxStaticBoxSizer& portSizer( *new wxStaticBoxSizer( wxVERTICAL, this, wxsFormat(_("Port %u"), port+1) ) );
|
||||
portSizer += m_panel_cardinfo[port] | pxExpand;
|
||||
|
||||
*this += portSizer | StdExpand();
|
||||
}
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Standard::Apply()
|
||||
{
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Standard::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
}
|
||||
|
||||
Panels::McdConfigPanel_Multitap::McdConfigPanel_Multitap(wxWindow *parent, int port) : _parent( parent )
|
||||
{
|
||||
m_port = port;
|
||||
|
||||
m_check_Multitap = new pxCheckBox( this, wxsFormat(_("Enable Multitap on Port %u"), m_port+1) );
|
||||
m_check_Multitap->SetFont( wxFont( m_check_Multitap->GetFont().GetPointSize()+1, wxFONTFAMILY_MODERN, wxNORMAL, wxNORMAL, false, L"Lucida Console" ) );
|
||||
|
||||
Connect( m_check_Multitap->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(McdConfigPanel_Multitap::OnMultitapChecked));
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Multitap::OnMultitapChecked( wxCommandEvent& evt )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Multitap::Apply()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Panels::McdConfigPanel_Multitap::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
using namespace Panels;
|
||||
using namespace pxSizerFlags;
|
||||
|
||||
Dialogs::McdConfigDialog::McdConfigDialog( wxWindow* parent )
|
||||
: BaseConfigurationDialog( parent, _("MemoryCard Settings - PCSX2"), wxGetApp().GetImgList_Config(), 600 )
|
||||
{
|
||||
SetName( GetNameStatic() );
|
||||
|
||||
// [TODO] : Discover and use a good multitap port icon! Possibility might be a
|
||||
// simple 3x memorycards icon, in cascading form.
|
||||
// (for now everything defaults to the redundant memorycard icon)
|
||||
|
||||
const AppImageIds::ConfigIds& cfgid( wxGetApp().GetImgId().Config );
|
||||
|
||||
AddPage<McdConfigPanel_Toggles> ( wxLt("Settings"), cfgid.MemoryCard );
|
||||
AddPage<McdConfigPanel_Standard> ( wxLt("Slots 1/2"), cfgid.MemoryCard );
|
||||
AddPage<McdConfigPanel_Multitap> ( wxLt("Multitap 1"), cfgid.MemoryCard );
|
||||
AddPage<McdConfigPanel_Multitap2> ( wxLt("Multitap 2"), cfgid.MemoryCard );
|
||||
|
||||
//MSW_ListView_SetIconSpacing( m_listbook, m_idealWidth );
|
||||
|
||||
*this += StdPadding;
|
||||
*this += new wxStaticLine( this ) | pxExpand;
|
||||
*this += StdPadding;
|
||||
*this += new MemoryCardListPanel( this ) | pxExpand;
|
||||
|
||||
AddOkCancel();
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
#include "ModalPopups.h"
|
||||
#include "Panels/ConfigurationPanels.h"
|
||||
|
||||
#include <wx/filepicker.h>
|
||||
//#include <wx/filepicker.h>
|
||||
|
||||
using namespace Panels;
|
||||
|
||||
|
@ -34,7 +34,6 @@ Dialogs::SysConfigDialog::SysConfigDialog(wxWindow* parent)
|
|||
|
||||
const AppImageIds::ConfigIds& cfgid( wxGetApp().GetImgId().Config );
|
||||
|
||||
AddPage<MemoryCardsPanel> ( wxLt("MemoryCards"), cfgid.MemoryCard );
|
||||
AddPage<CpuPanelEE> ( wxLt("EE/IOP"), cfgid.Cpu );
|
||||
AddPage<CpuPanelVU> ( wxLt("VUs"), cfgid.Cpu );
|
||||
AddPage<VideoPanel> ( wxLt("GS"), cfgid.Video );
|
||||
|
@ -44,8 +43,7 @@ Dialogs::SysConfigDialog::SysConfigDialog(wxWindow* parent)
|
|||
|
||||
MSW_ListView_SetIconSpacing( m_listbook, m_idealWidth );
|
||||
|
||||
// For some reason adding pages un-does the Apply button, so we need to re-disable it here.
|
||||
FindWindow( wxID_APPLY )->Disable();
|
||||
AddOkCancel();
|
||||
}
|
||||
|
||||
Dialogs::AppConfigDialog::AppConfigDialog(wxWindow* parent)
|
||||
|
@ -60,6 +58,5 @@ Dialogs::AppConfigDialog::AppConfigDialog(wxWindow* parent)
|
|||
|
||||
MSW_ListView_SetIconSpacing( m_listbook, GetClientSize().GetWidth() );
|
||||
|
||||
// For some reason adding pages un-does the Apply button, so we need to re-disable it here.
|
||||
FindWindow( wxID_APPLY )->Disable();
|
||||
AddOkCancel();
|
||||
}
|
||||
|
|
|
@ -17,13 +17,38 @@
|
|||
#include "App.h"
|
||||
|
||||
|
||||
// This is called from InvokeAction after various affinity and state checks have verified the
|
||||
// message as executable. Override this when possible. Only override InvokeAction if you
|
||||
wxString SysExecEvent::GetEventName() const
|
||||
{
|
||||
pxFail( "Warning: Unnamed SysExecutor Event! Please overload GetEventName() in all SysExecEvent derived classes." );
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
wxString SysExecEvent::GetEventMessage() const
|
||||
{
|
||||
return GetEventName();
|
||||
}
|
||||
|
||||
// This is called from _DoInvokeEvent after various affinity and state checks have verified the
|
||||
// message as executable. Override this when possible. Only override _DoInvokeEvent if you
|
||||
// need some kind of additional low-level ability.
|
||||
void SysExecEvent::_DoInvoke()
|
||||
void SysExecEvent::InvokeEvent()
|
||||
{
|
||||
}
|
||||
|
||||
// This is called by _DoInvokeEvent *always* -- even when exceptions occur during InvokeEvent(),
|
||||
// making this function a bit like a C# 'finally' block (try/catch/finally -- a nice feature lacking
|
||||
// from C++ prior to the new C++0x10 standard).
|
||||
//
|
||||
// This function calls PostResult by default, and should be invoked by derived classes overriding
|
||||
// CleanupEvent(), unless you want to change the PostResult behavior.
|
||||
void SysExecEvent::CleanupEvent()
|
||||
{
|
||||
PostResult();
|
||||
}
|
||||
|
||||
// Transports the specified exception to the thread/context that invoked this event.
|
||||
// Events are run from a try/catch block in the event handler that automatically transports
|
||||
// exceptions as neeeded, so there shouldn't be much need to use this method directly.
|
||||
void SysExecEvent::SetException( BaseException* ex )
|
||||
{
|
||||
if( !ex ) return;
|
||||
|
@ -55,14 +80,15 @@ void SysExecEvent::SetException( const BaseException& ex )
|
|||
}
|
||||
|
||||
|
||||
// This method calls _DoInvoke after performing some setup and affinity checks.
|
||||
// Override _DoInvoke instead, which is the intended method of implementing derived class invocation.
|
||||
void SysExecEvent::InvokeAction()
|
||||
// This method calls _DoInvoke after performing some setup, exception handling, and
|
||||
// affinity checks. For implementing behavior of your event, override _DoInvoke
|
||||
// instead, which is the intended method of implementing derived class invocation.
|
||||
void SysExecEvent::_DoInvokeEvent()
|
||||
{
|
||||
//pxAssumeDev( !IsBeingDeleted(), "Attempted to process a deleted SysExecutor event." );
|
||||
AffinityAssert_AllowFrom_SysExecutor();
|
||||
try {
|
||||
_DoInvoke();
|
||||
InvokeEvent();
|
||||
}
|
||||
catch( BaseException& ex )
|
||||
{
|
||||
|
@ -73,19 +99,32 @@ void SysExecEvent::InvokeAction()
|
|||
SetException( new Exception::RuntimeError(ex) );
|
||||
}
|
||||
|
||||
PostResult();
|
||||
CleanupEvent();
|
||||
}
|
||||
|
||||
// Posts an empty result to the invoking context/thread of this message, if one exists.
|
||||
// If the invoking thread posted the event in non-blocking fashion then no action is
|
||||
// taken.
|
||||
void SysExecEvent::PostResult() const
|
||||
{
|
||||
if( m_sync ) m_sync->PostResult();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// pxEvtHandler Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
pxEvtHandler::pxEvtHandler()
|
||||
{
|
||||
AtomicExchange( m_Quitting, false );
|
||||
m_qpc_Start = 0;
|
||||
}
|
||||
|
||||
// Puts the event queue into Shutdown mode, which does *not* immediately stop nor cancel
|
||||
// the queue's processing. Instead it marks the queue inaccessible to all new events
|
||||
// and continues procesing queued events for critical events that should not be ignored.
|
||||
// (typically these are shutdown events critical to closing the app cleanly). Once
|
||||
// all such events have been processed, the thread is stopped.
|
||||
//
|
||||
void pxEvtHandler::ShutdownQueue()
|
||||
{
|
||||
if( m_Quitting ) return;
|
||||
|
@ -108,48 +147,73 @@ struct ScopedThreadCancelDisable
|
|||
}
|
||||
};
|
||||
|
||||
void pxEvtHandler::ProcessPendingEvents()
|
||||
void pxEvtHandler::ProcessEvents( pxEvtList& list )
|
||||
{
|
||||
ScopedLock synclock( m_mtx_pending );
|
||||
|
||||
pxEvtList::iterator node;
|
||||
while( node = m_pendingEvents.begin(), node != m_pendingEvents.end() )
|
||||
while( node = list.begin(), node != list.end() )
|
||||
{
|
||||
ScopedPtr<SysExecEvent> deleteMe(wx_static_cast(SysExecEvent *, *node));
|
||||
ScopedPtr<SysExecEvent> deleteMe(*node);
|
||||
|
||||
m_pendingEvents.erase( node );
|
||||
list.erase( node );
|
||||
if( !m_Quitting || deleteMe->IsCriticalEvent() )
|
||||
{
|
||||
// Some messages can be blocking, so we should release the mutex lock
|
||||
// to avoid having cases where the main thread deadlocks simply trying
|
||||
// to add a message to the queue.
|
||||
// Some messages can be blocking, so we should release the mutex lock while
|
||||
// processing, to avoid having cases where the main thread deadlocks simply
|
||||
// trying to add a message to the queue due to the basic mutex acquire needed.
|
||||
|
||||
m_qpc_Start = GetCPUTicks();
|
||||
|
||||
synclock.Release();
|
||||
|
||||
DevCon.WriteLn( L"(pxEvtHandler) Executing Event: %s [%s]", deleteMe->GetEventName().c_str(), deleteMe->AllowCancelOnExit() ? L"Cancelable" : L"Noncancelable" );
|
||||
|
||||
if( deleteMe->AllowCancelOnExit() )
|
||||
deleteMe->InvokeAction();
|
||||
deleteMe->_DoInvokeEvent();
|
||||
else
|
||||
{
|
||||
ScopedThreadCancelDisable thr_cancel_scope;
|
||||
deleteMe->InvokeAction();
|
||||
deleteMe->_DoInvokeEvent();
|
||||
}
|
||||
|
||||
u64 qpc_end = GetCPUTicks();
|
||||
DevCon.WriteLn( L"(pxEvtHandler) Event '%s' completed in %dms", deleteMe->GetEventName().c_str(), ((qpc_end-m_qpc_Start)*100) / GetTickFrequency() );
|
||||
|
||||
synclock.Acquire();
|
||||
m_qpc_Start = 0; // lets the main thread know the message completed.
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLn( L"(pxEvtHandler:Skipping Event) %s", deleteMe->GetEventName().c_str() );
|
||||
Console.WriteLn( L"(pxEvtHandler) Skipping Event: %s", deleteMe->GetEventName().c_str() );
|
||||
deleteMe->PostResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method is provided for wxWidgets API conformance.
|
||||
void pxEvtHandler::ProcessIdleEvents()
|
||||
{
|
||||
ProcessEvents( m_idleEvents );
|
||||
}
|
||||
|
||||
void pxEvtHandler::ProcessPendingEvents()
|
||||
{
|
||||
ProcessEvents( m_pendingEvents );
|
||||
}
|
||||
|
||||
// This method is provided for wxWidgets API conformance. I like to use PostEvent instead
|
||||
// since it's remenicient of PostMessage in Windows (and behaves rather similarly).
|
||||
void pxEvtHandler::AddPendingEvent( SysExecEvent& evt )
|
||||
{
|
||||
PostEvent( evt );
|
||||
}
|
||||
|
||||
// Adds an event to the event queue in non-blocking fashion. The thread executing this
|
||||
// event queue will be woken up if it's idle/sleeping.
|
||||
// IMPORTANT: The pointer version of this function will *DELETE* the event object passed
|
||||
// to it automatically when the event has been executed. If you are using a scoped event
|
||||
// you should use the Reference/Handle overload instead!
|
||||
//
|
||||
void pxEvtHandler::PostEvent( SysExecEvent* evt )
|
||||
{
|
||||
if( !evt ) return;
|
||||
|
@ -171,16 +235,33 @@ void pxEvtHandler::PostEvent( SysExecEvent* evt )
|
|||
|
||||
void pxEvtHandler::PostEvent( const SysExecEvent& evt )
|
||||
{
|
||||
PostEvent( evt.Clone() );
|
||||
}
|
||||
|
||||
void pxEvtHandler::PostIdleEvent( SysExecEvent* evt )
|
||||
{
|
||||
if( !evt ) return;
|
||||
|
||||
if( m_Quitting )
|
||||
{
|
||||
evt.PostResult();
|
||||
evt->PostResult();
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedLock synclock( m_mtx_pending );
|
||||
m_pendingEvents.push_back( evt.Clone() );
|
||||
if( m_pendingEvents.size() == 1)
|
||||
|
||||
if( m_idleEvents.size() == 0)
|
||||
{
|
||||
m_pendingEvents.push_back( evt );
|
||||
m_wakeup.Post();
|
||||
}
|
||||
else
|
||||
m_idleEvents.push_back( evt );
|
||||
}
|
||||
|
||||
void pxEvtHandler::PostIdleEvent( const SysExecEvent& evt )
|
||||
{
|
||||
PostIdleEvent( evt.Clone() );
|
||||
}
|
||||
|
||||
void pxEvtHandler::ProcessEvent( SysExecEvent& evt )
|
||||
|
@ -193,23 +274,7 @@ void pxEvtHandler::ProcessEvent( SysExecEvent& evt )
|
|||
sync.WaitForResult();
|
||||
}
|
||||
else
|
||||
evt.InvokeAction();
|
||||
}
|
||||
|
||||
bool pxEvtHandler::SelfProcessMethod( FnType_Void* method )
|
||||
{
|
||||
if( wxThread::GetCurrentId() != m_OwnerThreadId )
|
||||
{
|
||||
SynchronousActionState sync;
|
||||
SysExecEvent_Method evt(method);
|
||||
evt.SetSyncState( sync );
|
||||
PostEvent( evt );
|
||||
sync.WaitForResult();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
evt._DoInvokeEvent();
|
||||
}
|
||||
|
||||
void pxEvtHandler::ProcessEvent( SysExecEvent* evt )
|
||||
|
@ -226,13 +291,38 @@ void pxEvtHandler::ProcessEvent( SysExecEvent* evt )
|
|||
else
|
||||
{
|
||||
ScopedPtr<SysExecEvent> deleteMe( evt );
|
||||
deleteMe->InvokeAction();
|
||||
deleteMe->_DoInvokeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
bool pxEvtHandler::ProcessMethodSelf( FnType_Void* method )
|
||||
{
|
||||
if( wxThread::GetCurrentId() != m_OwnerThreadId )
|
||||
{
|
||||
SynchronousActionState sync;
|
||||
SysExecEvent_MethodVoid evt(method);
|
||||
evt.SetSyncState( sync );
|
||||
PostEvent( evt );
|
||||
sync.WaitForResult();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// This method invokes the derived class Idle implementations (if any) and then enters
|
||||
// the sleep state until such time that new messages are received.
|
||||
//
|
||||
// FUTURE: Processes idle messages from the idle message queue (not implemented yet).
|
||||
//
|
||||
// Extending: Derived classes should override _DoIdle instead, unless it is necessary
|
||||
// to implement post-wakeup behavior.
|
||||
//
|
||||
void pxEvtHandler::Idle()
|
||||
{
|
||||
DoIdle();
|
||||
ProcessIdleEvents();
|
||||
_DoIdle();
|
||||
m_wakeup.WaitWithoutYield();
|
||||
}
|
||||
|
||||
|
@ -244,6 +334,9 @@ void pxEvtHandler::SetActiveThread()
|
|||
// --------------------------------------------------------------------------------------
|
||||
// WaitingForThreadedTaskDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Note: currently unused (legacy code). May be utilized at a later date, so I'm leaving
|
||||
// it in (for now!)
|
||||
//
|
||||
class WaitingForThreadedTaskDialog
|
||||
: public wxDialogWithHelpers
|
||||
{
|
||||
|
@ -303,6 +396,7 @@ ExecutorThread::ExecutorThread( pxEvtHandler* evthandler )
|
|||
m_EvtHandler = evthandler;
|
||||
}
|
||||
|
||||
// Exposes the internal pxEvtHandler::ShutdownQueue API. See pxEvtHandler for details.
|
||||
void ExecutorThread::ShutdownQueue()
|
||||
{
|
||||
if( !m_EvtHandler || m_EvtHandler->IsShuttingDown() ) return;
|
||||
|
@ -310,6 +404,7 @@ void ExecutorThread::ShutdownQueue()
|
|||
Block();
|
||||
}
|
||||
|
||||
// Exposes the internal pxEvtHandler::PostEvent API. See pxEvtHandler for details.
|
||||
void ExecutorThread::PostEvent( SysExecEvent* evt )
|
||||
{
|
||||
if( !pxAssert( m_EvtHandler ) ) return;
|
||||
|
@ -322,6 +417,20 @@ void ExecutorThread::PostEvent( const SysExecEvent& evt )
|
|||
m_EvtHandler->PostEvent( evt );
|
||||
}
|
||||
|
||||
// Exposes the internal pxEvtHandler::PostIdleEvent API. See pxEvtHandler for details.
|
||||
void ExecutorThread::PostIdleEvent( SysExecEvent* evt )
|
||||
{
|
||||
if( !pxAssert( m_EvtHandler ) ) return;
|
||||
m_EvtHandler->PostIdleEvent( evt );
|
||||
}
|
||||
|
||||
void ExecutorThread::PostIdleEvent( const SysExecEvent& evt )
|
||||
{
|
||||
if( !pxAssert( m_EvtHandler ) ) return;
|
||||
m_EvtHandler->PostIdleEvent( evt );
|
||||
}
|
||||
|
||||
// Exposes the internal pxEvtHandler::ProcessEvent API. See pxEvtHandler for details.
|
||||
void ExecutorThread::ProcessEvent( SysExecEvent* evt )
|
||||
{
|
||||
if( m_EvtHandler )
|
||||
|
@ -329,7 +438,7 @@ void ExecutorThread::ProcessEvent( SysExecEvent* evt )
|
|||
else
|
||||
{
|
||||
ScopedPtr<SysExecEvent> deleteMe( evt );
|
||||
deleteMe->InvokeAction();
|
||||
deleteMe->_DoInvokeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +447,7 @@ void ExecutorThread::ProcessEvent( SysExecEvent& evt )
|
|||
if( m_EvtHandler )
|
||||
m_EvtHandler->ProcessEvent( evt );
|
||||
else
|
||||
evt.InvokeAction();
|
||||
evt._DoInvokeEvent();
|
||||
}
|
||||
|
||||
void ExecutorThread::OnStart()
|
||||
|
@ -379,7 +488,7 @@ void ExecutorThread::OnCleanupInThread()
|
|||
// This event is called when the SysExecutorThread's timer triggers, which means the
|
||||
// VM/system task has taken an oddly long period of time to complete. The task is able
|
||||
// to invoke a modal dialog from here that will grant the user some options for handling
|
||||
// the unresponsive thread.
|
||||
// the unresponsive task.
|
||||
void Pcsx2App::OnSysExecutorTaskTimeout( wxTimerEvent& evt )
|
||||
{
|
||||
if( !SysExecutorThread.IsRunning() ) return;
|
||||
|
|
|
@ -155,7 +155,8 @@ void MainEmuFrame::ConnectMenus()
|
|||
#define ConnectMenuRange( id_start, inc, handler ) \
|
||||
Connect( id_start, id_start + inc, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainEmuFrame::handler) )
|
||||
|
||||
ConnectMenu( MenuId_Config_SysSettings, Menu_ConfigSettings_Click );
|
||||
ConnectMenu( MenuId_Config_SysSettings, Menu_SysSettings_Click );
|
||||
ConnectMenu( MenuId_Config_McdSettings, Menu_McdSettings_Click );
|
||||
ConnectMenu( MenuId_Config_AppSettings, Menu_AppSettings_Click );
|
||||
ConnectMenu( MenuId_Config_BIOS, Menu_SelectBios_Click );
|
||||
ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_Click );
|
||||
|
@ -412,6 +413,7 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
|
|||
|
||||
m_menuConfig.Append(MenuId_Config_SysSettings, _("Emulation &Settings") );
|
||||
m_menuConfig.Append(MenuId_Config_AppSettings, _("App Settings") );
|
||||
m_menuConfig.Append(MenuId_Config_McdSettings, _("&MemoryCards") );
|
||||
m_menuConfig.AppendSeparator();
|
||||
|
||||
|
||||
|
|
|
@ -162,7 +162,8 @@ protected:
|
|||
void OnFocus( wxFocusEvent& evt );
|
||||
void OnActivate( wxActivateEvent& evt );
|
||||
|
||||
void Menu_ConfigSettings_Click(wxCommandEvent &event);
|
||||
void Menu_SysSettings_Click(wxCommandEvent &event);
|
||||
void Menu_McdSettings_Click(wxCommandEvent &event);
|
||||
void Menu_AppSettings_Click(wxCommandEvent &event);
|
||||
void Menu_SelectBios_Click(wxCommandEvent &event);
|
||||
void Menu_ResetAllSettings_Click(wxCommandEvent &event);
|
||||
|
|
|
@ -38,11 +38,16 @@ void MainEmuFrame::SaveEmuOptions()
|
|||
}
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_ConfigSettings_Click(wxCommandEvent &event)
|
||||
void MainEmuFrame::Menu_SysSettings_Click(wxCommandEvent &event)
|
||||
{
|
||||
AppOpenDialog<SysConfigDialog>( this );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_McdSettings_Click(wxCommandEvent &event)
|
||||
{
|
||||
AppOpenDialog<McdConfigDialog>( this );
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_AppSettings_Click(wxCommandEvent &event)
|
||||
{
|
||||
AppOpenDialog<AppConfigDialog>( this );
|
||||
|
@ -425,7 +430,7 @@ public:
|
|||
wxString GetEventName() const { return L"ToggleSuspendResume"; }
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
if( CoreThread.IsOpen() )
|
||||
CoreThread.Suspend();
|
||||
|
@ -447,7 +452,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
sApp.SysShutdown();
|
||||
sApp.SysExecute();
|
||||
|
|
|
@ -102,7 +102,7 @@ FileMemoryCard::FileMemoryCard()
|
|||
// [TODO] : Add memcard size detection and report it to the console log.
|
||||
// (8MB, 256Mb, whatever)
|
||||
|
||||
NTFS_CompressFile( str, g_Conf->McdEnableNTFS );
|
||||
NTFS_CompressFile( str, g_Conf->McdCompressNTFS );
|
||||
|
||||
if( !m_file[port][slot].Open( str.c_str(), L"r+b" ) )
|
||||
{
|
||||
|
|
|
@ -64,7 +64,7 @@ BaseMessageBoxEvent::BaseMessageBoxEvent( const BaseMessageBoxEvent& event )
|
|||
}
|
||||
|
||||
// Thread Safety: Must be called from the GUI thread ONLY.
|
||||
void BaseMessageBoxEvent::_DoInvoke()
|
||||
void BaseMessageBoxEvent::InvokeEvent()
|
||||
{
|
||||
int result = _DoDialog();
|
||||
if( m_state ) m_state->PostResult( result );
|
||||
|
@ -104,7 +104,7 @@ pxMessageBoxEvent::pxMessageBoxEvent( const pxMessageBoxEvent& event )
|
|||
|
||||
int pxMessageBoxEvent::_DoDialog() const
|
||||
{
|
||||
return pxMessageDialog( m_Content, m_Title, m_Buttons );
|
||||
return pxMessageDialog( m_Title, m_Content, m_Buttons );
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "ConfigurationPanels.h"
|
||||
#include "MemoryCardListView.h"
|
||||
#include "MemoryCardPanels.h"
|
||||
|
||||
#include <wx/filepicker.h>
|
||||
#include <wx/ffile.h>
|
||||
|
@ -81,7 +81,7 @@ static int EnumerateMemoryCards( McdList& dest, const wxArrayString& files )
|
|||
// =====================================================================================================
|
||||
// MemoryCardListPanel
|
||||
// =====================================================================================================
|
||||
MemoryCardListPanel::MemoryCardListPanel( wxWindow* parent )
|
||||
Panels::MemoryCardListPanel::MemoryCardListPanel( wxWindow* parent )
|
||||
: BaseSelectorPanel( parent )
|
||||
{
|
||||
m_FolderPicker = new DirPickerPanel( this, FolderId_MemoryCards,
|
||||
|
@ -113,18 +113,16 @@ MemoryCardListPanel::MemoryCardListPanel( wxWindow* parent )
|
|||
*this += m_listview | pxExpand;
|
||||
*this += s_buttons | pxExpand;
|
||||
|
||||
m_listview->SetMinSize( wxSize( wxDefaultCoord, 120 ) );
|
||||
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
m_listview->SetMinSize( wxSize( m_idealWidth, 120 ) );
|
||||
|
||||
Disable();
|
||||
}
|
||||
|
||||
void MemoryCardListPanel::Apply()
|
||||
void Panels::MemoryCardListPanel::Apply()
|
||||
{
|
||||
}
|
||||
|
||||
void MemoryCardListPanel::AppStatusEvent_OnSettingsApplied()
|
||||
void Panels::MemoryCardListPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -139,7 +137,7 @@ bool Panels::MemoryCardListPanel::OnDropFiles(wxCoord x, wxCoord y, const wxArra
|
|||
return false;
|
||||
}
|
||||
|
||||
bool MemoryCardListPanel::ValidateEnumerationStatus()
|
||||
bool Panels::MemoryCardListPanel::ValidateEnumerationStatus()
|
||||
{
|
||||
bool validated = true;
|
||||
|
||||
|
@ -163,7 +161,7 @@ bool MemoryCardListPanel::ValidateEnumerationStatus()
|
|||
return validated;
|
||||
}
|
||||
|
||||
void MemoryCardListPanel::DoRefresh()
|
||||
void Panels::MemoryCardListPanel::DoRefresh()
|
||||
{
|
||||
if( !m_KnownCards ) return;
|
||||
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
/* 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 "AppCommon.h"
|
||||
|
||||
#include <wx/dnd.h>
|
||||
#include <wx/listctrl.h>
|
||||
|
||||
namespace Panels
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
// McdListItem
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct McdListItem
|
||||
{
|
||||
uint SizeInMB; // size, in megabytes!
|
||||
bool IsFormatted;
|
||||
wxDateTime DateCreated;
|
||||
wxDateTime DateModified;
|
||||
wxFileName Filename; // full pathname
|
||||
|
||||
int Port;
|
||||
int Slot;
|
||||
|
||||
McdListItem()
|
||||
{
|
||||
Port = -1;
|
||||
Slot = -1;
|
||||
}
|
||||
|
||||
bool operator==( const McdListItem& right ) const
|
||||
{
|
||||
return
|
||||
OpEqu(SizeInMB) && OpEqu(IsFormatted) &&
|
||||
OpEqu(DateCreated) && OpEqu(DateModified) &&
|
||||
OpEqu(Filename);
|
||||
}
|
||||
|
||||
bool operator!=( const McdListItem& right ) const
|
||||
{
|
||||
return operator==( right );
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<McdListItem> McdList;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MemoryCardListView
|
||||
// --------------------------------------------------------------------------------------
|
||||
class MemoryCardListView : public wxListView
|
||||
{
|
||||
typedef wxListView _parent;
|
||||
|
||||
protected:
|
||||
McdList* m_KnownCards;
|
||||
|
||||
public:
|
||||
virtual ~MemoryCardListView() throw() { }
|
||||
MemoryCardListView( wxWindow* parent );
|
||||
|
||||
virtual void OnListDrag(wxListEvent& evt);
|
||||
virtual void CreateColumns();
|
||||
virtual void AssignCardsList( McdList* knownCards, int length=0 );
|
||||
|
||||
protected:
|
||||
// Overrides for wxLC_VIRTUAL
|
||||
virtual wxString OnGetItemText(long item, long column) const;
|
||||
virtual int OnGetItemImage(long item) const;
|
||||
virtual int OnGetItemColumnImage(long item, long column) const;
|
||||
virtual wxListItemAttr *OnGetItemAttr(long item) const;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MemoryCardListPanel
|
||||
// --------------------------------------------------------------------------------------
|
||||
class MemoryCardListPanel
|
||||
: public BaseSelectorPanel
|
||||
, public wxFileDropTarget
|
||||
{
|
||||
protected:
|
||||
DirPickerPanel* m_FolderPicker;
|
||||
MemoryCardListView* m_listview;
|
||||
ScopedPtr<McdList> m_KnownCards;
|
||||
|
||||
public:
|
||||
virtual ~MemoryCardListPanel() throw() {}
|
||||
MemoryCardListPanel( wxWindow* parent );
|
||||
|
||||
protected:
|
||||
virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames);
|
||||
|
||||
virtual void Apply();
|
||||
virtual void AppStatusEvent_OnSettingsApplied();
|
||||
virtual void DoRefresh();
|
||||
virtual bool ValidateEnumerationStatus();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MemoryCardInfoPanel
|
||||
// --------------------------------------------------------------------------------------
|
||||
class MemoryCardInfoPanel : public BaseApplicableConfigPanel
|
||||
{
|
||||
protected:
|
||||
uint m_port;
|
||||
uint m_slot;
|
||||
|
||||
//wxStaticText* m_label;
|
||||
wxTextCtrl* m_label;
|
||||
|
||||
public:
|
||||
virtual ~MemoryCardInfoPanel() throw() {}
|
||||
MemoryCardInfoPanel( wxWindow* parent, uint port, uint slot );
|
||||
void Apply();
|
||||
|
||||
protected:
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
void paintEvent( wxPaintEvent& evt );
|
||||
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,192 @@
|
|||
/* 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 "AppCommon.h"
|
||||
|
||||
#include <wx/dnd.h>
|
||||
#include <wx/listctrl.h>
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// McdListItem
|
||||
// --------------------------------------------------------------------------------------
|
||||
struct McdListItem
|
||||
{
|
||||
uint SizeInMB; // size, in megabytes!
|
||||
bool IsFormatted;
|
||||
wxDateTime DateCreated;
|
||||
wxDateTime DateModified;
|
||||
wxFileName Filename; // full pathname
|
||||
|
||||
int Port;
|
||||
int Slot;
|
||||
|
||||
McdListItem()
|
||||
{
|
||||
Port = -1;
|
||||
Slot = -1;
|
||||
}
|
||||
|
||||
bool operator==( const McdListItem& right ) const
|
||||
{
|
||||
return
|
||||
OpEqu(SizeInMB) && OpEqu(IsFormatted) &&
|
||||
OpEqu(DateCreated) && OpEqu(DateModified) &&
|
||||
OpEqu(Filename);
|
||||
}
|
||||
|
||||
bool operator!=( const McdListItem& right ) const
|
||||
{
|
||||
return operator==( right );
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<McdListItem> McdList;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MemoryCardListView
|
||||
// --------------------------------------------------------------------------------------
|
||||
class MemoryCardListView : public wxListView
|
||||
{
|
||||
typedef wxListView _parent;
|
||||
|
||||
protected:
|
||||
McdList* m_KnownCards;
|
||||
|
||||
public:
|
||||
virtual ~MemoryCardListView() throw() { }
|
||||
MemoryCardListView( wxWindow* parent );
|
||||
|
||||
virtual void OnListDrag(wxListEvent& evt);
|
||||
virtual void CreateColumns();
|
||||
virtual void AssignCardsList( McdList* knownCards, int length=0 );
|
||||
|
||||
protected:
|
||||
// Overrides for wxLC_VIRTUAL
|
||||
virtual wxString OnGetItemText(long item, long column) const;
|
||||
virtual int OnGetItemImage(long item) const;
|
||||
virtual int OnGetItemColumnImage(long item, long column) const;
|
||||
virtual wxListItemAttr *OnGetItemAttr(long item) const;
|
||||
};
|
||||
|
||||
namespace Panels
|
||||
{
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MemoryCardListPanel
|
||||
// --------------------------------------------------------------------------------------
|
||||
class MemoryCardListPanel
|
||||
: public BaseSelectorPanel
|
||||
, public wxFileDropTarget
|
||||
{
|
||||
protected:
|
||||
DirPickerPanel* m_FolderPicker;
|
||||
MemoryCardListView* m_listview;
|
||||
ScopedPtr<McdList> m_KnownCards;
|
||||
|
||||
public:
|
||||
virtual ~MemoryCardListPanel() throw() {}
|
||||
MemoryCardListPanel( wxWindow* parent );
|
||||
|
||||
protected:
|
||||
virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames);
|
||||
|
||||
virtual void Apply();
|
||||
virtual void AppStatusEvent_OnSettingsApplied();
|
||||
virtual void DoRefresh();
|
||||
virtual bool ValidateEnumerationStatus();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// MemoryCardInfoPanel
|
||||
// --------------------------------------------------------------------------------------
|
||||
class MemoryCardInfoPanel : public BaseApplicableConfigPanel
|
||||
{
|
||||
protected:
|
||||
uint m_port;
|
||||
uint m_slot;
|
||||
|
||||
wxFileName m_filename;
|
||||
|
||||
public:
|
||||
virtual ~MemoryCardInfoPanel() throw() {}
|
||||
MemoryCardInfoPanel( wxWindow* parent, uint port, uint slot );
|
||||
void Apply();
|
||||
|
||||
protected:
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
void paintEvent( wxPaintEvent& evt );
|
||||
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// McdConfigPanel_Toggles / McdConfigPanel_Standard / McdConfigPanel_Multitap
|
||||
// --------------------------------------------------------------------------------------
|
||||
class McdConfigPanel_Toggles : public BaseApplicableConfigPanel
|
||||
{
|
||||
typedef BaseApplicableConfigPanel _parent;
|
||||
|
||||
protected:
|
||||
pxCheckBox* m_check_Ejection;
|
||||
|
||||
#ifdef __WXMSW__
|
||||
pxCheckBox* m_check_CompressNTFS;
|
||||
#endif
|
||||
|
||||
public:
|
||||
McdConfigPanel_Toggles( wxWindow* parent );
|
||||
virtual ~McdConfigPanel_Toggles() throw() { }
|
||||
void Apply();
|
||||
|
||||
protected:
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
class McdConfigPanel_Standard : public BaseApplicableConfigPanel
|
||||
{
|
||||
typedef BaseApplicableConfigPanel _parent;
|
||||
|
||||
protected:
|
||||
MemoryCardInfoPanel* m_panel_cardinfo[2];
|
||||
|
||||
public:
|
||||
McdConfigPanel_Standard( wxWindow* parent );
|
||||
virtual ~McdConfigPanel_Standard() throw() { }
|
||||
void Apply();
|
||||
|
||||
protected:
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
class McdConfigPanel_Multitap : public BaseApplicableConfigPanel
|
||||
{
|
||||
typedef BaseApplicableConfigPanel _parent;
|
||||
|
||||
protected:
|
||||
int m_port;
|
||||
|
||||
pxCheckBox* m_check_Multitap;
|
||||
|
||||
public:
|
||||
McdConfigPanel_Multitap( wxWindow* parent, int port=0 );
|
||||
virtual ~McdConfigPanel_Multitap() throw() { }
|
||||
void Apply();
|
||||
|
||||
protected:
|
||||
void OnMultitapChecked( wxCommandEvent& evt );
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
};
|
||||
|
||||
};
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "ConfigurationPanels.h"
|
||||
#include "MemoryCardListView.h"
|
||||
#include "MemoryCardPanels.h"
|
||||
|
||||
#include "Dialogs/ConfigurationDialog.h"
|
||||
|
||||
|
@ -81,7 +81,7 @@ MemoryCardListView::MemoryCardListView( wxWindow* parent )
|
|||
Connect( wxEVT_COMMAND_LIST_BEGIN_DRAG, wxListEventHandler(MemoryCardListView::OnListDrag));
|
||||
}
|
||||
|
||||
void Panels::MemoryCardListView::OnListDrag(wxListEvent& evt)
|
||||
void MemoryCardListView::OnListDrag(wxListEvent& evt)
|
||||
{
|
||||
evt.Skip();
|
||||
|
||||
|
@ -94,7 +94,7 @@ void Panels::MemoryCardListView::OnListDrag(wxListEvent& evt)
|
|||
}
|
||||
|
||||
// return the text for the given column of the given item
|
||||
wxString Panels::MemoryCardListView::OnGetItemText(long item, long column) const
|
||||
wxString MemoryCardListView::OnGetItemText(long item, long column) const
|
||||
{
|
||||
if( m_KnownCards == NULL ) return _parent::OnGetItemText(item, column);
|
||||
|
||||
|
@ -123,19 +123,19 @@ wxString Panels::MemoryCardListView::OnGetItemText(long item, long column) const
|
|||
// return the icon for the given item. In report view, OnGetItemImage will
|
||||
// only be called for the first column. See OnGetItemColumnImage for
|
||||
// details.
|
||||
int Panels::MemoryCardListView::OnGetItemImage(long item) const
|
||||
int MemoryCardListView::OnGetItemImage(long item) const
|
||||
{
|
||||
return _parent::OnGetItemImage( item );
|
||||
}
|
||||
|
||||
// return the icon for the given item and column.
|
||||
int Panels::MemoryCardListView::OnGetItemColumnImage(long item, long column) const
|
||||
int MemoryCardListView::OnGetItemColumnImage(long item, long column) const
|
||||
{
|
||||
return _parent::OnGetItemColumnImage( item, column );
|
||||
}
|
||||
|
||||
// return the attribute for the item (may return NULL if none)
|
||||
wxListItemAttr* Panels::MemoryCardListView::OnGetItemAttr(long item) const
|
||||
wxListItemAttr* MemoryCardListView::OnGetItemAttr(long item) const
|
||||
{
|
||||
wxListItemAttr* retval = _parent::OnGetItemAttr(item);
|
||||
//const McdListItem& it( (*m_KnownCards)[item] );
|
||||
|
@ -155,34 +155,58 @@ MemoryCardInfoPanel::MemoryCardInfoPanel( wxWindow* parent, uint port, uint slot
|
|||
SetMinSize( wxSize(128, 48) );
|
||||
|
||||
Connect( wxEVT_PAINT, wxPaintEventHandler(MemoryCardInfoPanel::paintEvent) );
|
||||
}
|
||||
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
static void DrawTextCentered( wxDC& dc, const wxString msg )
|
||||
{
|
||||
int tWidth, tHeight;
|
||||
dc.GetTextExtent( msg, &tWidth, &tHeight );
|
||||
dc.DrawText( msg, (dc.GetSize().GetWidth() - tWidth) / 2, 0 );
|
||||
}
|
||||
|
||||
void MemoryCardInfoPanel::paintEvent(wxPaintEvent & evt)
|
||||
{
|
||||
// Collect Info and Format Strings
|
||||
|
||||
wxString fname( m_filename.GetFullPath() );
|
||||
if( fname.IsEmpty() ) fname = _("No Card (empty)");
|
||||
|
||||
// Create DC and plot some text (and images!)
|
||||
|
||||
wxPaintDC dc( this );
|
||||
wxFont normal( dc.GetFont() );
|
||||
wxFont bold( normal );
|
||||
normal.SetWeight( wxNORMAL );
|
||||
bold.SetWeight( wxBOLD );
|
||||
|
||||
wxFont woot( dc.GetFont() );
|
||||
woot.SetWeight( wxBOLD );
|
||||
dc.SetFont( woot );
|
||||
dc.SetFont( bold );
|
||||
DrawTextCentered( dc, fname );
|
||||
|
||||
wxString msg;
|
||||
msg = _("No Card (empty)");
|
||||
|
||||
int tWidth, tHeight;
|
||||
dc.GetTextExtent( msg, &tWidth, &tHeight );
|
||||
|
||||
dc.DrawText( msg, (dc.GetSize().GetWidth() - tWidth) / 2, 0 );
|
||||
//dc.DrawCircle( dc.GetSize().GetWidth()/2, 24, dc.GetSize().GetWidth()/4 );
|
||||
}
|
||||
|
||||
void MemoryCardInfoPanel::Apply()
|
||||
{
|
||||
if( m_filename.IsDir() )
|
||||
{
|
||||
throw Exception::CannotApplySettings( this,
|
||||
wxLt("Cannot use or create memorycard: the filename is an existing directory."),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if( m_filename.FileExists() )
|
||||
{
|
||||
// TODO : Prompt user to create non-existing files. For now we just creat them implicitly.
|
||||
}
|
||||
|
||||
g_Conf->Mcd[m_port][m_slot].Filename = m_filename;
|
||||
}
|
||||
|
||||
void MemoryCardInfoPanel::AppStatusEvent_OnSettingsApplied()
|
||||
{
|
||||
m_filename = g_Conf->Mcd[m_port][m_slot].Filename;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,73 +218,20 @@ Panels::MemoryCardsPanel::MemoryCardsPanel( wxWindow* parent )
|
|||
{
|
||||
m_panel_AllKnownCards = new MemoryCardListPanel( this );
|
||||
|
||||
m_idealWidth -= 48;
|
||||
m_check_Ejection = new pxCheckBox( this,
|
||||
_("Auto-eject memorycards when loading savestates"),
|
||||
pxE( ".Dialog:Memorycards:EnableEjection",
|
||||
L"Avoids memorycard corruption by forcing games to re-index card contents after "
|
||||
L"loading from savestates. May not be compatible with all games (Guitar Hero)."
|
||||
)
|
||||
);
|
||||
m_idealWidth += 48;
|
||||
|
||||
wxPanelWithHelpers* columns[2];
|
||||
|
||||
for( uint port=0; port<2; ++port )
|
||||
{
|
||||
columns[port] = new wxPanelWithHelpers( this, wxVERTICAL );
|
||||
columns[port]->SetIdealWidth( (columns[port]->GetIdealWidth()-12) / 2 );
|
||||
|
||||
/*m_check_Multitap[port] = new pxCheckBox( columns[port], wxsFormat(_("Enable Multitap on Port %u"), port+1) );
|
||||
m_check_Multitap[port]->SetClientData( (void*) port );
|
||||
m_check_Multitap[port]->SetFont( wxFont( m_check_Multitap[port]->GetFont().GetPointSize()+1, wxFONTFAMILY_MODERN, wxNORMAL, wxNORMAL, false, L"Lucida Console" ) );*/
|
||||
|
||||
for( uint slot=0; slot<1; ++slot )
|
||||
{
|
||||
m_panel_cardinfo[port][slot] = new MemoryCardInfoPanel( columns[port], port, slot );
|
||||
m_panel_cardinfo[port][slot] = new MemoryCardInfoPanel( this, port, slot );
|
||||
}
|
||||
|
||||
//Connect( m_check_Multitap[port]->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(MemoryCardsPanel::OnMultitapChecked));
|
||||
}
|
||||
|
||||
// ------------------------------------
|
||||
// Sizer / Layout Section
|
||||
// ------------------------------------
|
||||
|
||||
wxFlexGridSizer* s_table = new wxFlexGridSizer( 2 );
|
||||
s_table->AddGrowableCol( 0 );
|
||||
s_table->AddGrowableCol( 1 );
|
||||
|
||||
for( uint port=0; port<2; ++port )
|
||||
{
|
||||
wxStaticBoxSizer& portSizer( *new wxStaticBoxSizer( wxVERTICAL, columns[port], wxsFormat(_("Port %u"), port+1) ) );
|
||||
|
||||
*columns[port] += portSizer | SubGroup();
|
||||
|
||||
portSizer += m_panel_cardinfo[port][0] | SubGroup();
|
||||
//portSizer += new wxStaticLine( columns[port] ) | pxExpand.Border( wxTOP, StdPadding );
|
||||
//portSizer += m_check_Multitap[port] | pxCenter.Border( wxBOTTOM, StdPadding );
|
||||
|
||||
/*for( uint slot=1; slot<4; ++slot )
|
||||
{
|
||||
//portSizer += new wxStaticText( columns[port], wxID_ANY, wxsFormat(_("Slot #%u"), slot+1) ); // | pxCenter;
|
||||
wxStaticBoxSizer& staticbox( *new wxStaticBoxSizer( wxVERTICAL, columns[port] ) );
|
||||
staticbox += m_panel_cardinfo[port][slot] | pxExpand;
|
||||
portSizer += staticbox | SubGroup();
|
||||
|
||||
}*/
|
||||
|
||||
*s_table += columns[port] | StdExpand();
|
||||
}
|
||||
|
||||
wxBoxSizer& s_checks( *new wxBoxSizer( wxVERTICAL ) );
|
||||
s_checks += m_check_Ejection;
|
||||
|
||||
*this += s_table | pxExpand;
|
||||
*this += m_panel_AllKnownCards | StdExpand();
|
||||
*this += s_checks | StdExpand();
|
||||
|
||||
AppStatusEvent_OnSettingsApplied();
|
||||
}
|
||||
|
||||
void Panels::MemoryCardsPanel::OnMultitapChecked( wxCommandEvent& evt )
|
||||
|
|
|
@ -14,16 +14,19 @@
|
|||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "App.h"
|
||||
#include "AppSaveStates.h"
|
||||
#include "Plugins.h"
|
||||
#include "Utilities/ScopedPtr.h"
|
||||
#include "ConfigurationPanels.h"
|
||||
#include "Dialogs/ModalPopups.h"
|
||||
|
||||
#include <wx/dynlib.h>
|
||||
#include <wx/dir.h>
|
||||
|
||||
#include "App.h"
|
||||
#include "AppSaveStates.h"
|
||||
#include "Plugins.h"
|
||||
#include "ConfigurationPanels.h"
|
||||
|
||||
#include "Dialogs/ModalPopups.h"
|
||||
|
||||
#include "Utilities/ThreadingDialogs.h"
|
||||
|
||||
// Allows us to force-disable threading for debugging/troubleshooting
|
||||
static const bool DisableThreading =
|
||||
#ifdef __LINUX__
|
||||
|
@ -36,20 +39,20 @@ using namespace pxSizerFlags;
|
|||
using namespace Threading;
|
||||
|
||||
BEGIN_DECLARE_EVENT_TYPES()
|
||||
DECLARE_EVENT_TYPE(pxEVT_EnumeratedNext, -1)
|
||||
DECLARE_EVENT_TYPE(pxEvt_EnumeratedNext, -1)
|
||||
DECLARE_EVENT_TYPE(pxEvt_EnumerationFinished, -1)
|
||||
DECLARE_EVENT_TYPE(pxEVT_ShowStatusBar, -1)
|
||||
DECLARE_EVENT_TYPE(pxEvt_SysExecEventComplete, -1)
|
||||
END_DECLARE_EVENT_TYPES()
|
||||
|
||||
DEFINE_EVENT_TYPE(pxEVT_EnumeratedNext)
|
||||
DEFINE_EVENT_TYPE(pxEvt_EnumeratedNext);
|
||||
DEFINE_EVENT_TYPE(pxEvt_EnumerationFinished);
|
||||
DEFINE_EVENT_TYPE(pxEVT_ShowStatusBar);
|
||||
DEFINE_EVENT_TYPE(pxEvt_SysExecEventComplete)
|
||||
|
||||
typedef s32 (CALLBACK* TestFnptr)();
|
||||
typedef void (CALLBACK* ConfigureFnptr)();
|
||||
|
||||
static const wxString failed_separator( L"-------- Unsupported Plugins --------" );
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
class NotEnumerablePlugin : public BadStream
|
||||
|
@ -138,28 +141,20 @@ public:
|
|||
// --------------------------------------------------------------------------------------
|
||||
// ApplyPluginsDialog
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ApplyPluginsDialog : public wxDialogWithHelpers
|
||||
class ApplyPluginsDialog : public WaitForTaskDialog
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS_NO_COPY(ApplyPluginsDialog)
|
||||
|
||||
typedef wxDialogWithHelpers _parent;
|
||||
|
||||
protected:
|
||||
BaseApplicableConfigPanel* m_panel;
|
||||
ScopedPtr<BaseException> m_Exception;
|
||||
SynchronousActionState m_sync;
|
||||
BaseApplicableConfigPanel* m_panel;
|
||||
|
||||
public:
|
||||
ApplyPluginsDialog( BaseApplicableConfigPanel* panel=NULL );
|
||||
virtual ~ApplyPluginsDialog() throw() {}
|
||||
|
||||
virtual void RethrowException();
|
||||
virtual int ShowModal();
|
||||
|
||||
BaseApplicableConfigPanel* GetApplicableConfigPanel() const { return m_panel; }
|
||||
|
||||
protected:
|
||||
void OnSysExecComplete( wxCommandEvent& evt );
|
||||
};
|
||||
|
||||
|
||||
|
@ -184,7 +179,7 @@ public:
|
|||
virtual ApplyOverValidStateEvent *Clone() const { return new ApplyOverValidStateEvent(*this); }
|
||||
|
||||
protected:
|
||||
void _DoInvoke();
|
||||
void InvokeEvent();
|
||||
};
|
||||
|
||||
|
||||
|
@ -193,10 +188,14 @@ protected:
|
|||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_ApplyPlugins : public SysExecEvent
|
||||
{
|
||||
typedef SysExecEvent _parent;
|
||||
|
||||
protected:
|
||||
ApplyPluginsDialog* m_dialog;
|
||||
|
||||
public:
|
||||
wxString GetEventName() const { return L"PluginSelectorPanel::ApplyPlugins"; }
|
||||
|
||||
virtual ~SysExecEvent_ApplyPlugins() throw() {}
|
||||
SysExecEvent_ApplyPlugins* Clone() const { return new SysExecEvent_ApplyPlugins( *this ); }
|
||||
|
||||
|
@ -207,19 +206,27 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke();
|
||||
void InvokeEvent();
|
||||
void CleanupEvent();
|
||||
|
||||
void PostFinishToDialog();
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(ApplyPluginsDialog, wxDialogWithHelpers)
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ApplyPluginsDialog Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
IMPLEMENT_DYNAMIC_CLASS(ApplyPluginsDialog, WaitForTaskDialog)
|
||||
|
||||
ApplyPluginsDialog::ApplyPluginsDialog( BaseApplicableConfigPanel* panel )
|
||||
: wxDialogWithHelpers( NULL, _("Applying settings..."), wxVERTICAL )
|
||||
: WaitForTaskDialog( _("Applying settings...") )
|
||||
{
|
||||
Connect( pxEvt_SysExecEventComplete, wxCommandEventHandler(ApplyPluginsDialog::OnSysExecComplete) );
|
||||
GetSysExecutorThread().PostEvent( new SysExecEvent_ApplyPlugins( this, m_sync ) );
|
||||
}
|
||||
|
||||
void ApplyOverValidStateEvent::_DoInvoke()
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ApplyOverValidStateEvent Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
void ApplyOverValidStateEvent::InvokeEvent()
|
||||
{
|
||||
wxDialogWithHelpers dialog( m_owner, _("Shutdown PS2 virtual machine?"), wxVERTICAL );
|
||||
|
||||
|
@ -237,7 +244,10 @@ void ApplyOverValidStateEvent::_DoInvoke()
|
|||
throw Exception::CannotApplySettings( m_owner->GetApplicableConfigPanel(), "Cannot apply settings: canceled by user because plugins changed while the emulation state was active.", false );
|
||||
}
|
||||
|
||||
void SysExecEvent_ApplyPlugins::_DoInvoke()
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_ApplyPlugins Implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
void SysExecEvent_ApplyPlugins::InvokeEvent()
|
||||
{
|
||||
ScopedCoreThreadPause paused_core;
|
||||
|
||||
|
@ -261,36 +271,26 @@ void SysExecEvent_ApplyPlugins::_DoInvoke()
|
|||
LoadPluginsImmediate();
|
||||
CoreThread.RecoverState();
|
||||
|
||||
wxCommandEvent tevt( pxEvt_SysExecEventComplete );
|
||||
m_dialog->GetEventHandler()->AddPendingEvent( tevt );
|
||||
PostFinishToDialog();
|
||||
|
||||
closed_core.AllowResume();
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
|
||||
|
||||
void ApplyPluginsDialog::OnSysExecComplete( wxCommandEvent& evt )
|
||||
void SysExecEvent_ApplyPlugins::PostFinishToDialog()
|
||||
{
|
||||
evt.Skip();
|
||||
m_sync.WaitForResult();
|
||||
EndModal( wxID_OK );
|
||||
if( !m_dialog ) return;
|
||||
wxCommandEvent tevt( pxEvt_ThreadedTaskComplete );
|
||||
m_dialog->GetEventHandler()->AddPendingEvent( tevt );
|
||||
m_dialog = NULL;
|
||||
}
|
||||
|
||||
void ApplyPluginsDialog::RethrowException()
|
||||
void SysExecEvent_ApplyPlugins::CleanupEvent()
|
||||
{
|
||||
if( m_Exception ) m_Exception->Rethrow();
|
||||
PostFinishToDialog();
|
||||
_parent::CleanupEvent();
|
||||
}
|
||||
|
||||
int ApplyPluginsDialog::ShowModal()
|
||||
{
|
||||
int result = _parent::ShowModal();
|
||||
RethrowException();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static const wxString failed_separator( L"-------- Unsupported Plugins --------" );
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PluginSelectorPanel::StatusPanel implementations
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -420,7 +420,7 @@ Panels::PluginSelectorPanel::PluginSelectorPanel( wxWindow* parent, int idealWid
|
|||
//s_main.Add( refresh );
|
||||
//Connect( refresh->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PluginSelectorPanel::OnRefresh ) );
|
||||
|
||||
Connect( pxEVT_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) );
|
||||
Connect( pxEvt_EnumeratedNext, wxCommandEventHandler( PluginSelectorPanel::OnProgress ) );
|
||||
Connect( pxEvt_EnumerationFinished, wxCommandEventHandler( PluginSelectorPanel::OnEnumComplete ) );
|
||||
Connect( pxEVT_ShowStatusBar, wxCommandEventHandler( PluginSelectorPanel::OnShowStatusBar ) );
|
||||
Connect( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler( PluginSelectorPanel::OnPluginSelected ) );
|
||||
|
@ -494,24 +494,9 @@ void Panels::PluginSelectorPanel::Apply()
|
|||
// ----------------------------------------------------------------------------
|
||||
// Plugin names are not up-to-date -- RELOAD!
|
||||
|
||||
ApplyPluginsDialog applyDlg( this );
|
||||
|
||||
wxBoxSizer& paddedMsg( *new wxBoxSizer( wxHORIZONTAL ) );
|
||||
paddedMsg += 24;
|
||||
paddedMsg += applyDlg.Heading(_("Applying Settings..."));
|
||||
paddedMsg += 24;
|
||||
|
||||
applyDlg += 12;
|
||||
applyDlg += paddedMsg;
|
||||
applyDlg += 12;
|
||||
applyDlg += new wxButton( &applyDlg, wxID_CANCEL ) | pxCenter;
|
||||
applyDlg += 6;
|
||||
|
||||
//applyDlg.GetEventHandler()->AddPendingEvent( );
|
||||
|
||||
try
|
||||
{
|
||||
if( wxID_CANCEL == applyDlg.ShowModal() )
|
||||
if( wxID_CANCEL == ApplyPluginsDialog( this ).ShowModal() )
|
||||
throw Exception::CannotApplySettings( this, "User canceled plugin load process.", false );
|
||||
}
|
||||
catch( Exception::PluginError& ex )
|
||||
|
@ -794,7 +779,7 @@ void Panels::PluginSelectorPanel::EnumThread::DoNextPlugin( int curidx )
|
|||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
}
|
||||
|
||||
wxCommandEvent yay( pxEVT_EnumeratedNext );
|
||||
wxCommandEvent yay( pxEvt_EnumeratedNext );
|
||||
yay.SetClientData( this );
|
||||
yay.SetExtraLong( curidx );
|
||||
m_master.GetEventHandler()->AddPendingEvent( yay );
|
||||
|
|
|
@ -40,16 +40,54 @@ bool States_isSlotUsed(int num)
|
|||
return wxFileExists( SaveStateBase::GetFilename( num ) );
|
||||
}
|
||||
|
||||
static volatile u32 IsSavingOrLoading = false;
|
||||
|
||||
class SysExecEvent_ClearSavingLoadingFlag : public SysExecEvent
|
||||
{
|
||||
public:
|
||||
wxString GetEventName() const { return L"ClearSavingLoadingFlag"; }
|
||||
|
||||
virtual ~SysExecEvent_ClearSavingLoadingFlag() throw() { }
|
||||
SysExecEvent_ClearSavingLoadingFlag()
|
||||
{
|
||||
}
|
||||
|
||||
SysExecEvent_ClearSavingLoadingFlag* Clone() const { return new SysExecEvent_ClearSavingLoadingFlag(); }
|
||||
|
||||
protected:
|
||||
void InvokeEvent()
|
||||
{
|
||||
AtomicExchange(IsSavingOrLoading, false);
|
||||
}
|
||||
};
|
||||
|
||||
void States_FreezeCurrentSlot()
|
||||
{
|
||||
if( AtomicExchange(IsSavingOrLoading, true) )
|
||||
{
|
||||
Console.WriteLn( "Load or save action is already pending." );
|
||||
return;
|
||||
}
|
||||
|
||||
GSchangeSaveState( StatesC, SaveStateBase::GetFilename( StatesC ).ToUTF8() );
|
||||
StateCopy_SaveToSlot( StatesC );
|
||||
|
||||
GetSysExecutorThread().PostIdleEvent( SysExecEvent_ClearSavingLoadingFlag() );
|
||||
}
|
||||
|
||||
void States_DefrostCurrentSlot()
|
||||
{
|
||||
if( AtomicExchange(IsSavingOrLoading, true) )
|
||||
{
|
||||
Console.WriteLn( "Load or save action is already pending." );
|
||||
return;
|
||||
}
|
||||
|
||||
GSchangeSaveState( StatesC, SaveStateBase::GetFilename( StatesC ).ToUTF8() );
|
||||
StateCopy_LoadFromSlot( StatesC );
|
||||
|
||||
GetSysExecutorThread().PostIdleEvent( SysExecEvent_ClearSavingLoadingFlag() );
|
||||
|
||||
//SysStatus( wxsFormat( _("Loaded State (slot %d)"), StatesC ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ static void SaveStateFile_ReadHeader( IStreamReader& thr )
|
|||
//
|
||||
class gzipReader : public IStreamReader
|
||||
{
|
||||
DeclareNoncopyableObject(gzipReader);
|
||||
|
||||
protected:
|
||||
wxString m_filename;
|
||||
gzFile m_gzfp;
|
||||
|
@ -100,6 +102,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static bool IsSavingOrLoading = false;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_DownloadState
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -111,6 +116,8 @@ protected:
|
|||
VmStateBuffer* m_dest_buffer;
|
||||
|
||||
public:
|
||||
wxString GetEventName() const { return L"VM_Download"; }
|
||||
|
||||
virtual ~SysExecEvent_DownloadState() throw() {}
|
||||
SysExecEvent_DownloadState* Clone() const { return new SysExecEvent_DownloadState( *this ); }
|
||||
SysExecEvent_DownloadState( VmStateBuffer* dest=&state_buffer )
|
||||
|
@ -118,10 +125,11 @@ public:
|
|||
m_dest_buffer = dest;
|
||||
}
|
||||
|
||||
bool IsCriticalEvent() const { return true; }
|
||||
bool AllowCancelOnExit() const { return false; }
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
ScopedCoreThreadPause paused_core;
|
||||
|
||||
|
@ -130,10 +138,61 @@ protected:
|
|||
|
||||
memSavingState(m_dest_buffer).FreezeAll();
|
||||
|
||||
UI_EnableStateActions();
|
||||
paused_core.AllowResume();
|
||||
}
|
||||
};
|
||||
|
||||
// It's bad mojo to have savestates trying to read and write from the same file at the
|
||||
// same time. To prevent that we use this mutex lock, which is used by both the
|
||||
// CompressThread and the UnzipFromDisk events. (note that CompressThread locks the
|
||||
// mutex during OnStartInThread, which ensures that the ZipToDisk event blocks; preventing
|
||||
// the SysExecutor's Idle Event from re-enabing savestates and slots.)
|
||||
//
|
||||
static Mutex mtx_CompressToDisk;
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// CompressThread_VmState
|
||||
// --------------------------------------------------------------------------------------
|
||||
class VmStateZipThread : public CompressThread_gzip
|
||||
{
|
||||
typedef CompressThread_gzip _parent;
|
||||
|
||||
protected:
|
||||
ScopedLock m_lock_Compress;
|
||||
|
||||
public:
|
||||
VmStateZipThread( const wxString& file, VmStateBuffer* srcdata )
|
||||
: _parent( file, srcdata, SaveStateFile_WriteHeader )
|
||||
{
|
||||
m_lock_Compress.Assign(mtx_CompressToDisk);
|
||||
}
|
||||
|
||||
VmStateZipThread( const wxString& file, ScopedPtr<VmStateBuffer>& srcdata )
|
||||
: _parent( file, srcdata, SaveStateFile_WriteHeader )
|
||||
{
|
||||
m_lock_Compress.Assign(mtx_CompressToDisk);
|
||||
}
|
||||
|
||||
virtual ~VmStateZipThread() throw()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnStartInThread()
|
||||
{
|
||||
_parent::OnStartInThread();
|
||||
m_lock_Compress.Acquire();
|
||||
}
|
||||
|
||||
void OnCleanupInThread()
|
||||
{
|
||||
m_lock_Compress.Release();
|
||||
_parent::OnCleanupInThread();
|
||||
}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_ZipToDisk
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -144,7 +203,7 @@ protected:
|
|||
wxString m_filename;
|
||||
|
||||
public:
|
||||
wxString GetEventName() const { return L"SysState_ZipToDisk"; }
|
||||
wxString GetEventName() const { return L"VM_ZipToDisk"; }
|
||||
|
||||
virtual ~SysExecEvent_ZipToDisk() throw()
|
||||
{
|
||||
|
@ -153,7 +212,6 @@ public:
|
|||
|
||||
SysExecEvent_ZipToDisk* Clone() const { return new SysExecEvent_ZipToDisk( *this ); }
|
||||
|
||||
// Yep, gcc doesn't like >> again.
|
||||
SysExecEvent_ZipToDisk( ScopedPtr<VmStateBuffer>& src, const wxString& filename )
|
||||
: m_filename( filename )
|
||||
{
|
||||
|
@ -170,9 +228,9 @@ public:
|
|||
bool AllowCancelOnExit() const { return false; }
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
(new CompressThread_gzip( m_filename, m_src_buffer, SaveStateFile_WriteHeader ))->Start();
|
||||
(new VmStateZipThread( m_filename, m_src_buffer ))->Start();
|
||||
m_src_buffer = NULL;
|
||||
}
|
||||
};
|
||||
|
@ -188,25 +246,27 @@ class SysExecEvent_UnzipFromDisk : public SysExecEvent
|
|||
{
|
||||
protected:
|
||||
wxString m_filename;
|
||||
gzipReader m_gzreader;
|
||||
|
||||
public:
|
||||
wxString GetEventName() const { return L"SysState_UnzipFromDisk"; }
|
||||
wxString GetEventName() const { return L"VM_UnzipFromDisk"; }
|
||||
|
||||
virtual ~SysExecEvent_UnzipFromDisk() throw() {}
|
||||
SysExecEvent_UnzipFromDisk* Clone() const { return new SysExecEvent_UnzipFromDisk( *this ); }
|
||||
SysExecEvent_UnzipFromDisk( const wxString& filename )
|
||||
: m_filename( filename )
|
||||
, m_gzreader( filename )
|
||||
{
|
||||
SaveStateFile_ReadHeader( m_gzreader );
|
||||
}
|
||||
|
||||
wxString GetStreamName() const { return m_filename; }
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
ScopedLock lock( mtx_CompressToDisk );
|
||||
|
||||
gzipReader m_gzreader(m_filename );
|
||||
SaveStateFile_ReadHeader( m_gzreader );
|
||||
|
||||
// We use direct Suspend/Resume control here, since it's desirable that emulation
|
||||
// *ALWAYS* start execution after the new savestate is loaded.
|
||||
|
||||
|
@ -263,6 +323,8 @@ void StateCopy_FreezeToMem()
|
|||
|
||||
void StateCopy_SaveToFile( const wxString& file )
|
||||
{
|
||||
UI_DisableStateActions();
|
||||
|
||||
ScopedPtr<VmStateBuffer> zipbuf(new VmStateBuffer( L"Zippable Savestate" ));
|
||||
GetSysExecutorThread().PostEvent(new SysExecEvent_DownloadState( zipbuf ));
|
||||
GetSysExecutorThread().PostEvent(new SysExecEvent_ZipToDisk( zipbuf, file ));
|
||||
|
|
|
@ -70,18 +70,34 @@ void UI_EnableSysShutdown()
|
|||
|
||||
void UI_DisableSysActions()
|
||||
{
|
||||
if( wxGetApp().PostMethodMyself( &UI_DisableSysShutdown ) ) return;
|
||||
if( wxGetApp().PostMethodMyself( &UI_DisableSysActions ) ) return;
|
||||
|
||||
sMainFrame.EnableMenuItem( MenuId_Sys_Restart, false );
|
||||
sMainFrame.EnableMenuItem( MenuId_Sys_Shutdown, false );
|
||||
|
||||
_SaveLoadStuff( false );
|
||||
}
|
||||
|
||||
void UI_EnableSysActions()
|
||||
{
|
||||
if( wxGetApp().PostMethodMyself( &UI_EnableSysShutdown ) ) return;
|
||||
if( wxGetApp().PostMethodMyself( &UI_EnableSysActions ) ) return;
|
||||
|
||||
sMainFrame.EnableMenuItem( MenuId_Sys_Restart, true );
|
||||
sMainFrame.EnableMenuItem( MenuId_Sys_Shutdown, true );
|
||||
|
||||
_SaveLoadStuff( true );
|
||||
}
|
||||
|
||||
void UI_DisableStateActions()
|
||||
{
|
||||
if( wxGetApp().PostMethodMyself( &UI_DisableStateActions ) ) return;
|
||||
_SaveLoadStuff( false );
|
||||
}
|
||||
|
||||
void UI_EnableStateActions()
|
||||
{
|
||||
if( wxGetApp().PostMethodMyself( &UI_EnableStateActions ) ) return;
|
||||
_SaveLoadStuff( true );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,9 +23,25 @@
|
|||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent
|
||||
: public IActionInvocation
|
||||
, public ICloneable
|
||||
// Base class for all pxEvtHandler processable events.
|
||||
//
|
||||
// Rules for deriving:
|
||||
// * Override InvokeEvent(), *NOT* _DoInvokeEvent(). _DoInvokeEvent() performs setup and
|
||||
// wraps exceptions for transport to the invoking context/thread, and then itself calls
|
||||
// InvokeEvent() to perform the derived class implementation.
|
||||
//
|
||||
// * Derived classes must implement their own versions of an empty constructor and
|
||||
// Clone(), or else the class will fail to be copied to the event handler's thread
|
||||
// context correctly.
|
||||
//
|
||||
// * This class is not abstract, and gives no error if the invocation method is not
|
||||
// overridden: It can be used as a simple ping device against the event queue, Re-
|
||||
// awaking the invoking thread as soon as the queue has caught up to and processed
|
||||
// the event.
|
||||
//
|
||||
// * Avoid using virtual class inheritence. It's unreliable at best.
|
||||
//
|
||||
class SysExecEvent : public ICloneable
|
||||
{
|
||||
protected:
|
||||
SynchronousActionState* m_sync;
|
||||
|
@ -63,11 +79,11 @@ public:
|
|||
// data.
|
||||
virtual bool AllowCancelOnExit() const { return true; }
|
||||
|
||||
virtual void InvokeAction();
|
||||
virtual void _DoInvokeEvent();
|
||||
virtual void PostResult() const;
|
||||
|
||||
virtual wxString GetEventName() const { return wxEmptyString; }
|
||||
virtual wxString GetEventMessage() const { return wxEmptyString; }
|
||||
virtual wxString GetEventName() const;
|
||||
virtual wxString GetEventMessage() const;
|
||||
|
||||
virtual int GetResult()
|
||||
{
|
||||
|
@ -80,28 +96,31 @@ public:
|
|||
void SetException( const BaseException& ex );
|
||||
|
||||
protected:
|
||||
virtual void _DoInvoke();
|
||||
virtual void InvokeEvent();
|
||||
virtual void CleanupEvent();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SysExecEvent_Method
|
||||
// SysExecEvent_MethodVoid
|
||||
// --------------------------------------------------------------------------------------
|
||||
class SysExecEvent_Method : public SysExecEvent
|
||||
class SysExecEvent_MethodVoid : public SysExecEvent
|
||||
{
|
||||
protected:
|
||||
FnType_Void* m_method;
|
||||
|
||||
public:
|
||||
virtual ~SysExecEvent_Method() throw() {}
|
||||
SysExecEvent_Method* Clone() const { return new SysExecEvent_Method( *this ); }
|
||||
wxString GetEventName() const { return L"MethodVoid"; }
|
||||
|
||||
explicit SysExecEvent_Method( FnType_Void* method = NULL )
|
||||
virtual ~SysExecEvent_MethodVoid() throw() {}
|
||||
SysExecEvent_MethodVoid* Clone() const { return new SysExecEvent_MethodVoid( *this ); }
|
||||
|
||||
explicit SysExecEvent_MethodVoid( FnType_Void* method = NULL )
|
||||
{
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
protected:
|
||||
void _DoInvoke()
|
||||
void InvokeEvent()
|
||||
{
|
||||
if( m_method ) m_method();
|
||||
}
|
||||
|
@ -113,18 +132,39 @@ typedef std::list<SysExecEvent*> pxEvtList;
|
|||
// --------------------------------------------------------------------------------------
|
||||
// pxEvtHandler
|
||||
// --------------------------------------------------------------------------------------
|
||||
// wxWidgets Event Queue (wxEvtHandler) isn't thread-safe (uses static vars and checks/modifies wxApp globals
|
||||
// while processing), so it's useless to us. Have to roll our own. -_-
|
||||
// Purpose: To provide a safe environment for queuing tasks that must be executed in
|
||||
// sequential order (in blocking fashion). Unlike the wxWidgets event handlers, instances
|
||||
// of this handler can be stalled for extended periods of time without affecting the
|
||||
// responsiveness of the GUI or frame updates of the DirectX output windows. This class
|
||||
// is mostly intended to be used from the context of an ExecutorThread.
|
||||
//
|
||||
// Rationales:
|
||||
// * Using the main event handler of wxWidgets is dangerous because it must call itself
|
||||
// recursively when waiting on threaded events such as semaphore and mutexes. Thus,
|
||||
// tasks such as suspending the VM would invoke the event queue while waiting,
|
||||
// running events that expect the suspend to be complete while the suspend was still
|
||||
// pending.
|
||||
//
|
||||
// * wxWidgets Event Queue (wxEvtHandler) isn't thread-safe and isn't even
|
||||
// intended for use for anything other than wxWindow events (it uses static vars
|
||||
// and checks/modifies wxApp globals while processing), so it's useless to us.
|
||||
// Have to roll our own. -_-
|
||||
//
|
||||
class pxEvtHandler
|
||||
{
|
||||
protected:
|
||||
pxEvtList m_pendingEvents;
|
||||
pxEvtList m_idleEvents;
|
||||
|
||||
Threading::MutexRecursive m_mtx_pending;
|
||||
Threading::Semaphore m_wakeup;
|
||||
wxThreadIdType m_OwnerThreadId;
|
||||
volatile u32 m_Quitting;
|
||||
|
||||
// Used for performance measuring the execution of individual events,
|
||||
// and also for detecting deadlocks during message processing.
|
||||
volatile u64 m_qpc_Start;
|
||||
|
||||
public:
|
||||
pxEvtHandler();
|
||||
virtual ~pxEvtHandler() throw() {}
|
||||
|
@ -134,27 +174,33 @@ public:
|
|||
virtual void ShutdownQueue();
|
||||
bool IsShuttingDown() const { return !!m_Quitting; }
|
||||
|
||||
void ProcessEvents( pxEvtList& list );
|
||||
void ProcessPendingEvents();
|
||||
void ProcessIdleEvents();
|
||||
void Idle();
|
||||
|
||||
void AddPendingEvent( SysExecEvent& evt );
|
||||
void PostEvent( SysExecEvent* evt );
|
||||
void PostEvent( const SysExecEvent& evt );
|
||||
void PostIdleEvent( SysExecEvent* evt );
|
||||
void PostIdleEvent( const SysExecEvent& evt );
|
||||
|
||||
void ProcessEvent( SysExecEvent* evt );
|
||||
void ProcessEvent( SysExecEvent& evt );
|
||||
|
||||
bool SelfProcessMethod( FnType_Void* method );
|
||||
|
||||
void Idle();
|
||||
|
||||
bool ProcessMethodSelf( FnType_Void* method );
|
||||
void SetActiveThread();
|
||||
|
||||
protected:
|
||||
virtual void DoIdle() {}
|
||||
virtual void _DoIdle() {}
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ExecutorThread
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Threaded wrapper class for implementing pxEvtHandler. Simply create the desired
|
||||
// EvtHandler, start the thread, and enjoy queued event execution in fully blocking fashion.
|
||||
//
|
||||
class ExecutorThread : public Threading::PersistentThread
|
||||
{
|
||||
typedef Threading::PersistentThread _parent;
|
||||
|
@ -172,12 +218,15 @@ public:
|
|||
void PostEvent( SysExecEvent* evt );
|
||||
void PostEvent( const SysExecEvent& evt );
|
||||
|
||||
void PostIdleEvent( SysExecEvent* evt );
|
||||
void PostIdleEvent( const SysExecEvent& evt );
|
||||
|
||||
void ProcessEvent( SysExecEvent* evt );
|
||||
void ProcessEvent( SysExecEvent& evt );
|
||||
|
||||
bool SelfProcessMethod( void (*evt)() )
|
||||
bool ProcessMethodSelf( void (*evt)() )
|
||||
{
|
||||
return m_EvtHandler ? m_EvtHandler->SelfProcessMethod( evt ) : false;
|
||||
return m_EvtHandler ? m_EvtHandler->ProcessMethodSelf( evt ) : false;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -2059,6 +2059,10 @@
|
|||
RelativePath="..\..\gui\Dialogs\LogOptionsDialog.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Dialogs\McdConfigDialog.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Dialogs\ModalPopups.h"
|
||||
>
|
||||
|
@ -2610,7 +2614,7 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\gui\Panels\MemoryCardListView.h"
|
||||
RelativePath="..\..\gui\Panels\MemoryCardPanels.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
Loading…
Reference in New Issue