2010-01-08 07:11:33 +00:00
/* PCSX2 - PS2 Emulator for PCs
2010-05-03 14:08:02 +00:00
* Copyright ( C ) 2002 - 2010 PCSX2 Dev Team
2010-01-08 07:11:33 +00:00
*
* 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/>.
*/
2021-09-01 20:31:46 +00:00
# include "common/wxAppWithHelpers.h"
# include "common/ThreadingInternal.h"
# include "common/PersistentThread.h"
2010-04-27 13:12:03 +00:00
2016-06-14 22:17:37 +00:00
wxDEFINE_EVENT ( pxEvt_StartIdleEventTimer , wxCommandEvent ) ;
wxDEFINE_EVENT ( pxEvt_DeleteObject , wxCommandEvent ) ;
wxDEFINE_EVENT ( pxEvt_DeleteThread , wxCommandEvent ) ;
wxDEFINE_EVENT ( pxEvt_InvokeAction , pxActionEvent ) ;
wxDEFINE_EVENT ( pxEvt_SynchronousCommand , pxSynchronousCommandEvent ) ;
2010-04-27 13:12:03 +00:00
2019-05-12 03:43:47 +00:00
wxIMPLEMENT_DYNAMIC_CLASS ( pxSimpleEvent , wxEvent ) ;
2010-01-22 15:22:01 +00:00
2010-08-16 15:01:13 +00:00
ConsoleLogSource_App : : ConsoleLogSource_App ( )
{
2016-11-12 15:28:37 +00:00
static const TraceLogDescriptor myDesc =
{
L " AppEvents " , L " App Events " ,
pxLt ( " Includes idle event processing and some other uncommon event usages. " ) } ;
m_Descriptor = & myDesc ;
2010-08-16 15:01:13 +00:00
}
2010-08-06 05:46:09 +00:00
ConsoleLogSource_App pxConLog_App ;
2010-01-22 15:22:01 +00:00
2010-04-27 13:12:03 +00:00
void BaseDeletableObject : : DoDeletion ( )
2010-01-22 15:22:01 +00:00
{
2016-11-12 15:28:37 +00:00
wxAppWithHelpers * app = wxDynamicCast ( wxApp : : GetInstance ( ) , wxAppWithHelpers ) ;
pxAssert ( app ! = NULL ) ;
app - > DeleteObject ( * this ) ;
2010-01-22 15:22:01 +00:00
}
2010-01-08 07:11:33 +00:00
2010-05-03 13:51:46 +00:00
// --------------------------------------------------------------------------------------
// SynchronousActionState Implementations
// --------------------------------------------------------------------------------------
2016-11-12 15:28:37 +00:00
void SynchronousActionState : : SetException ( const BaseException & ex )
2010-05-10 17:59:03 +00:00
{
2016-11-12 15:28:37 +00:00
m_exception = ScopedExcept ( ex . Clone ( ) ) ;
2010-05-10 17:59:03 +00:00
}
2016-11-12 15:28:37 +00:00
void SynchronousActionState : : SetException ( BaseException * ex )
2010-05-10 17:59:03 +00:00
{
2016-11-12 15:28:37 +00:00
if ( ! m_posted ) {
m_exception = ScopedExcept ( ex ) ;
} else if ( wxTheApp ) {
// transport the exception to the main thread, since the message is fully
// asynchronous, or has already entered an asynchronous state. Message is sent
// as a non-blocking action since proper handling of user errors on async messages
// is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
// box to the user.
2010-05-10 17:59:03 +00:00
2016-11-12 15:28:37 +00:00
pxExceptionEvent ev ( ex ) ;
wxTheApp - > AddPendingEvent ( ev ) ;
}
2010-05-10 17:59:03 +00:00
}
2010-05-03 13:51:46 +00:00
void SynchronousActionState : : RethrowException ( ) const
{
2016-11-12 15:28:37 +00:00
if ( m_exception )
m_exception - > Rethrow ( ) ;
2010-05-03 13:51:46 +00:00
}
int SynchronousActionState : : WaitForResult ( )
{
2016-11-12 15:28:37 +00:00
m_sema . WaitNoCancel ( ) ;
RethrowException ( ) ;
return return_value ;
2010-05-03 13:51:46 +00:00
}
int SynchronousActionState : : WaitForResult_NoExceptions ( )
{
2016-11-12 15:28:37 +00:00
m_sema . WaitNoCancel ( ) ;
return return_value ;
2010-05-03 13:51:46 +00:00
}
2016-11-12 15:28:37 +00:00
void SynchronousActionState : : PostResult ( int res )
2010-05-03 13:51:46 +00:00
{
2016-11-12 15:28:37 +00:00
return_value = res ;
PostResult ( ) ;
2010-05-03 13:51:46 +00:00
}
void SynchronousActionState : : ClearResult ( )
{
2016-11-12 15:28:37 +00:00
m_posted = false ;
m_exception = NULL ;
2010-05-03 13:51:46 +00:00
}
void SynchronousActionState : : PostResult ( )
{
2016-11-12 15:28:37 +00:00
if ( m_posted )
return ;
m_posted = true ;
m_sema . Post ( ) ;
2010-05-03 13:51:46 +00:00
}
2010-01-08 07:11:33 +00:00
// --------------------------------------------------------------------------------------
2010-06-19 13:42:32 +00:00
// pxActionEvent Implementations
2010-01-08 07:11:33 +00:00
// --------------------------------------------------------------------------------------
2019-05-12 03:43:47 +00:00
wxIMPLEMENT_DYNAMIC_CLASS ( pxActionEvent , wxEvent ) ;
2010-01-08 07:11:33 +00:00
2016-11-12 15:28:37 +00:00
pxActionEvent : : pxActionEvent ( SynchronousActionState * sema , int msgtype )
: wxEvent ( 0 , msgtype )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
m_state = sema ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
pxActionEvent : : pxActionEvent ( SynchronousActionState & sema , int msgtype )
: wxEvent ( 0 , msgtype )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
m_state = & sema ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
pxActionEvent : : pxActionEvent ( const pxActionEvent & src )
: wxEvent ( src )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
m_state = src . m_state ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void pxActionEvent : : SetException ( const BaseException & ex )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
SetException ( ex . Clone ( ) ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void pxActionEvent : : SetException ( BaseException * ex )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
const wxString & prefix ( pxsFmt ( L " (%s) " , GetClassInfo ( ) - > GetClassName ( ) ) ) ;
ex - > DiagMsg ( ) = prefix + ex - > DiagMsg ( ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
if ( ! m_state ) {
ScopedExcept exptr ( ex ) ; // auto-delete it after handling.
ex - > Rethrow ( ) ;
}
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
m_state - > SetException ( ex ) ;
2010-04-27 13:12:03 +00:00
}
// --------------------------------------------------------------------------------------
// pxSynchronousCommandEvent
// --------------------------------------------------------------------------------------
2019-05-12 03:43:47 +00:00
wxIMPLEMENT_DYNAMIC_CLASS ( pxSynchronousCommandEvent , wxCommandEvent ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
pxSynchronousCommandEvent : : pxSynchronousCommandEvent ( SynchronousActionState * sema , wxEventType commandType , int winid )
: wxCommandEvent ( pxEvt_SynchronousCommand , winid )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
m_sync = sema ;
m_realEvent = commandType ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
pxSynchronousCommandEvent : : pxSynchronousCommandEvent ( SynchronousActionState & sema , wxEventType commandType , int winid )
: wxCommandEvent ( pxEvt_SynchronousCommand )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
m_sync = & sema ;
m_realEvent = commandType ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
pxSynchronousCommandEvent : : pxSynchronousCommandEvent ( SynchronousActionState * sema , const wxCommandEvent & evt )
: wxCommandEvent ( evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
m_sync = sema ;
m_realEvent = evt . GetEventType ( ) ;
SetEventType ( pxEvt_SynchronousCommand ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
pxSynchronousCommandEvent : : pxSynchronousCommandEvent ( SynchronousActionState & sema , const wxCommandEvent & evt )
: wxCommandEvent ( evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
m_sync = & sema ;
m_realEvent = evt . GetEventType ( ) ;
SetEventType ( pxEvt_SynchronousCommand ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
pxSynchronousCommandEvent : : pxSynchronousCommandEvent ( const pxSynchronousCommandEvent & src )
: wxCommandEvent ( src )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
m_sync = src . m_sync ;
m_realEvent = src . m_realEvent ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void pxSynchronousCommandEvent : : SetException ( const BaseException & ex )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
if ( ! m_sync )
ex . Rethrow ( ) ;
m_sync - > SetException ( ex ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void pxSynchronousCommandEvent : : SetException ( BaseException * ex )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
if ( ! m_sync ) {
ScopedExcept exptr ( ex ) ; // auto-delete it after handling.
ex - > Rethrow ( ) ;
}
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
m_sync - > SetException ( ex ) ;
2010-04-27 13:12:03 +00:00
}
// --------------------------------------------------------------------------------------
2010-06-19 13:42:32 +00:00
// pxRpcEvent
2010-04-27 13:12:03 +00:00
// --------------------------------------------------------------------------------------
// Unlike pxPingEvent, the Semaphore belonging to this event is typically posted when the
// invoked method is completed. If the method can be executed in non-blocking fashion then
// it should leave the semaphore postback NULL.
//
2010-06-19 13:42:32 +00:00
class pxRpcEvent : public pxActionEvent
2010-04-27 13:12:03 +00:00
{
2019-05-12 03:43:47 +00:00
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN ( pxRpcEvent ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
typedef pxActionEvent _parent ;
2010-04-27 13:12:03 +00:00
protected :
2016-11-12 15:28:37 +00:00
void ( * m_Method ) ( ) ;
2010-04-27 13:12:03 +00:00
public :
2017-05-06 11:00:55 +00:00
virtual ~ pxRpcEvent ( ) = default ;
2016-11-12 15:28:37 +00:00
virtual pxRpcEvent * Clone ( ) const { return new pxRpcEvent ( * this ) ; }
explicit pxRpcEvent ( void ( * method ) ( ) = NULL , SynchronousActionState * sema = NULL )
: pxActionEvent ( sema )
{
m_Method = method ;
}
explicit pxRpcEvent ( void ( * method ) ( ) , SynchronousActionState & sema )
: pxActionEvent ( sema )
{
m_Method = method ;
}
pxRpcEvent ( const pxRpcEvent & src )
: pxActionEvent ( src )
{
m_Method = src . m_Method ;
}
void SetMethod ( void ( * method ) ( ) )
{
m_Method = method ;
}
2010-04-27 13:12:03 +00:00
protected :
2016-11-12 15:28:37 +00:00
void InvokeEvent ( )
{
if ( m_Method )
m_Method ( ) ;
}
2010-04-27 13:12:03 +00:00
} ;
2019-05-12 03:43:47 +00:00
wxIMPLEMENT_DYNAMIC_CLASS ( pxRpcEvent , pxActionEvent ) ;
2010-04-27 13:12:03 +00:00
// --------------------------------------------------------------------------------------
// pxExceptionEvent implementations
// --------------------------------------------------------------------------------------
2016-11-12 15:28:37 +00:00
pxExceptionEvent : : pxExceptionEvent ( const BaseException & ex )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
m_except = ex . Clone ( ) ;
2010-04-27 13:12:03 +00:00
}
2010-05-03 13:51:46 +00:00
void pxExceptionEvent : : InvokeEvent ( )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
ScopedExcept deleteMe ( m_except ) ;
if ( deleteMe )
deleteMe - > Rethrow ( ) ;
2010-01-08 07:11:33 +00:00
}
2010-01-22 15:22:01 +00:00
// --------------------------------------------------------------------------------------
// wxAppWithHelpers Implementation
// --------------------------------------------------------------------------------------
2010-03-05 14:24:44 +00:00
//
// TODO : Ping dispatch and IdleEvent dispatch can be unified into a single dispatch, which
// would mean checking only one list of events per idle event, instead of two. (ie, ping
// events can be appended to the idle event list, instead of into their own custom list).
//
2019-05-12 03:43:47 +00:00
wxIMPLEMENT_DYNAMIC_CLASS ( wxAppWithHelpers , wxApp ) ;
2010-01-22 15:22:01 +00:00
2010-04-27 13:12:03 +00:00
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
// main thread.
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : PostMethod ( FnType_Void * method )
2010-03-05 14:24:44 +00:00
{
2016-11-12 15:28:37 +00:00
PostEvent ( pxRpcEvent ( method ) ) ;
2010-03-05 14:24:44 +00:00
}
2010-04-27 13:12:03 +00:00
// Posts a method to the main thread; non-blocking. Post occurs even when called from the
// main thread.
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : PostIdleMethod ( FnType_Void * method )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
pxRpcEvent evt ( method ) ;
AddIdleEvent ( evt ) ;
2010-04-27 13:12:03 +00:00
}
2010-01-08 07:11:33 +00:00
2010-06-19 13:42:32 +00:00
// Invokes the specified void method, or posts the method to the main thread if the calling
// thread is not Main. Action is blocking. For non-blocking method execution, use
// AppRpc_TryInvokeAsync.
//
// This function works something like setjmp/longjmp, in that the return value indicates if the
// function actually executed the specified method or not.
//
// Returns:
// FALSE if the method was not invoked (meaning this IS the main thread!)
// TRUE if the method was invoked.
//
2016-11-12 15:28:37 +00:00
bool wxAppWithHelpers : : Rpc_TryInvoke ( FnType_Void * method )
2010-06-19 13:42:32 +00:00
{
2016-11-12 15:28:37 +00:00
if ( wxThread : : IsMain ( ) )
return false ;
2010-06-19 13:42:32 +00:00
2016-11-12 15:28:37 +00:00
SynchronousActionState sync ;
PostEvent ( pxRpcEvent ( method , sync ) ) ;
sync . WaitForResult ( ) ;
2010-06-19 13:42:32 +00:00
2016-11-12 15:28:37 +00:00
return true ;
2010-06-19 13:42:32 +00:00
}
// Invokes the specified void method, or posts the method to the main thread if the calling
// thread is not Main. Action is non-blocking (asynchronous). For blocking method execution,
// use AppRpc_TryInvoke.
//
// This function works something like setjmp/longjmp, in that the return value indicates if the
// function actually executed the specified method or not.
//
// Returns:
// FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
// TRUE if the method was posted.
//
2016-11-12 15:28:37 +00:00
bool wxAppWithHelpers : : Rpc_TryInvokeAsync ( FnType_Void * method )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
if ( wxThread : : IsMain ( ) )
return false ;
PostEvent ( pxRpcEvent ( method ) ) ;
return true ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : ProcessMethod ( FnType_Void * method )
2010-01-22 15:22:01 +00:00
{
2016-11-12 15:28:37 +00:00
if ( wxThread : : IsMain ( ) ) {
method ( ) ;
return ;
}
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
SynchronousActionState sync ;
PostEvent ( pxRpcEvent ( method , sync ) ) ;
sync . WaitForResult ( ) ;
2010-03-05 14:24:44 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : PostEvent ( const wxEvent & evt )
2010-03-05 14:24:44 +00:00
{
2016-11-12 15:28:37 +00:00
// Const Cast is OK!
// Truth is, AddPendingEvent should be a const-qualified parameter, as
// it makes an immediate clone copy of the event -- but wxWidgets
// fails again in structured C/C++ design design. So I'm forcing it as such
// here. -- air
2010-03-05 14:24:44 +00:00
2016-11-12 15:28:37 +00:00
_parent : : AddPendingEvent ( const_cast < wxEvent & > ( evt ) ) ;
2010-04-27 13:12:03 +00:00
}
2010-03-05 14:24:44 +00:00
2016-11-12 15:28:37 +00:00
bool wxAppWithHelpers : : ProcessEvent ( wxEvent & evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
// Note: We can't do an automatic blocking post of the message here, because wxWidgets
// isn't really designed for it (some events return data to the caller via the event
// struct, and posting the event would require a temporary clone, where changes would
// be lost).
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
AffinityAssert_AllowFrom_MainUI ( ) ;
return _parent : : ProcessEvent ( evt ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
bool wxAppWithHelpers : : ProcessEvent ( wxEvent * evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
AffinityAssert_AllowFrom_MainUI ( ) ;
std : : unique_ptr < wxEvent > deleteMe ( evt ) ;
return _parent : : ProcessEvent ( * deleteMe ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
bool wxAppWithHelpers : : ProcessEvent ( pxActionEvent & evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
if ( wxThread : : IsMain ( ) )
return _parent : : ProcessEvent ( evt ) ;
else {
SynchronousActionState sync ;
evt . SetSyncState ( sync ) ;
AddPendingEvent ( evt ) ;
sync . WaitForResult ( ) ;
return true ;
}
2010-04-27 13:12:03 +00:00
}
2010-03-05 14:24:44 +00:00
2016-11-12 15:28:37 +00:00
bool wxAppWithHelpers : : ProcessEvent ( pxActionEvent * evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
if ( wxThread : : IsMain ( ) ) {
std : : unique_ptr < wxEvent > deleteMe ( evt ) ;
return _parent : : ProcessEvent ( * deleteMe ) ;
} else {
SynchronousActionState sync ;
evt - > SetSyncState ( sync ) ;
AddPendingEvent ( * evt ) ;
sync . WaitForResult ( ) ;
return true ;
}
2010-01-22 15:22:01 +00:00
}
2010-04-27 13:12:03 +00:00
void wxAppWithHelpers : : CleanUp ( )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
// I'm pretty sure the message pump is dead by now, which means we need to run through
// idle event list by hand and process the pending Deletion messages (all others can be
// ignored -- it's only deletions we want handled, and really we *could* ignore those too
// but I like to be tidy. -- air
2010-01-08 07:11:33 +00:00
2016-11-12 15:28:37 +00:00
//IdleEventDispatcher( "CleanUp" );
//DeletionDispatcher();
_parent : : CleanUp ( ) ;
2010-04-27 13:12:03 +00:00
}
2010-01-08 07:11:33 +00:00
2010-06-19 13:42:32 +00:00
// Executes the event with exception handling. If the event throws an exception, the exception
// will be neatly packaged and transported back to the thread that posted the event.
// This function is virtual, however overloading it is not recommended. Derrived classes
// should overload InvokeEvent() instead.
void pxActionEvent : : _DoInvokeEvent ( )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
AffinityAssert_AllowFrom_MainUI ( ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
try {
InvokeEvent ( ) ;
} catch ( BaseException & ex ) {
SetException ( ex ) ;
} catch ( std : : runtime_error & ex ) {
SetException ( new Exception : : RuntimeError ( ex ) ) ;
}
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
if ( m_state )
m_state - > PostResult ( ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : OnSynchronousCommand ( pxSynchronousCommandEvent & evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
AffinityAssert_AllowFrom_MainUI ( ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
pxAppLog . Write ( L " (App) Executing command event synchronously... " ) ;
evt . SetEventType ( evt . GetRealEventType ( ) ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
try {
ProcessEvent ( evt ) ;
} catch ( BaseException & ex ) {
evt . SetException ( ex ) ;
} catch ( std : : runtime_error & ex ) {
evt . SetException ( new Exception : : RuntimeError ( ex , evt . GetClassInfo ( ) - > GetClassName ( ) ) ) ;
}
2010-01-08 07:11:33 +00:00
2016-11-12 15:28:37 +00:00
if ( Semaphore * sema = evt . GetSemaphore ( ) )
sema - > Post ( ) ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : AddIdleEvent ( const wxEvent & evt )
2010-01-22 15:22:01 +00:00
{
2016-11-12 15:28:37 +00:00
ScopedLock lock ( m_IdleEventMutex ) ;
if ( m_IdleEventQueue . empty ( ) )
PostEvent ( wxCommandEvent ( pxEvt_StartIdleEventTimer ) ) ;
2010-01-22 15:22:01 +00:00
2016-11-12 15:28:37 +00:00
m_IdleEventQueue . push_back ( evt . Clone ( ) ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : OnStartIdleEventTimer ( wxCommandEvent & evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
ScopedLock lock ( m_IdleEventMutex ) ;
if ( ! m_IdleEventQueue . empty ( ) )
m_IdleEventTimer . Start ( 100 , true ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : IdleEventDispatcher ( const wxChar * action )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
// Recursion is possible thanks to modal dialogs being issued from the idle event handler.
// (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
// on each pass)
//static int __guard=0;
//RecursionGuard guard(__guard);
//if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
wxEventList postponed ;
wxEventList : : iterator node ;
2010-01-22 15:22:01 +00:00
2016-11-12 15:28:37 +00:00
ScopedLock lock ( m_IdleEventMutex ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
while ( node = m_IdleEventQueue . begin ( ) , node ! = m_IdleEventQueue . end ( ) ) {
std : : unique_ptr < wxEvent > deleteMe ( * node ) ;
m_IdleEventQueue . erase ( node ) ;
2010-05-07 03:20:58 +00:00
2016-11-12 15:28:37 +00:00
lock . Release ( ) ;
if ( ! Threading : : AllowDeletions ( ) & & ( deleteMe - > GetEventType ( ) = = pxEvt_DeleteThread ) ) {
// Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
// be deleted because those mutex/sema objects will become invalid and cause the pending
// thread to crash. So we disallow deletions when those waits are in action, and continue
// to postpone the deletion of the thread until such time that it is safe.
2010-08-06 05:46:09 +00:00
2016-11-12 15:28:37 +00:00
pxThreadLog . Write ( ( ( pxThread * ) ( ( wxCommandEvent * ) deleteMe . get ( ) ) - > GetClientData ( ) ) - > GetName ( ) , L " Deletion postponed due to mutex or semaphore dependency. " ) ;
postponed . push_back ( deleteMe . release ( ) ) ;
} else {
pxAppLog . Write ( L " (AppIdleQueue%s) Dispatching event '%s' " , action , deleteMe - > GetClassInfo ( ) - > GetClassName ( ) ) ;
ProcessEvent ( * deleteMe ) ; // dereference to prevent auto-deletion by ProcessEvent
}
lock . Acquire ( ) ;
}
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
m_IdleEventQueue = postponed ;
if ( ! m_IdleEventQueue . empty ( ) )
pxAppLog . Write ( L " (AppIdleQueue%s) %d events postponed due to dependencies. " , action , m_IdleEventQueue . size ( ) ) ;
2010-01-22 15:22:01 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : OnIdleEvent ( wxIdleEvent & evt )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
m_IdleEventTimer . Stop ( ) ;
IdleEventDispatcher ( ) ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : OnIdleEventTimeout ( wxTimerEvent & evt )
2010-03-05 14:24:44 +00:00
{
2016-11-12 15:28:37 +00:00
IdleEventDispatcher ( L " [Timeout] " ) ;
2010-03-05 14:24:44 +00:00
}
2010-01-08 07:11:33 +00:00
void wxAppWithHelpers : : Ping ( )
{
2016-11-12 15:28:37 +00:00
pxThreadLog . Write ( pxGetCurrentThreadName ( ) . c_str ( ) , L " App Event Ping Requested. " ) ;
2010-01-08 07:11:33 +00:00
2016-11-12 15:28:37 +00:00
SynchronousActionState sync ;
pxActionEvent evt ( sync ) ;
AddIdleEvent ( evt ) ;
sync . WaitForResult ( ) ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : PostCommand ( void * clientData , int evtType , int intParam , long longParam , const wxString & stringParam )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
wxCommandEvent evt ( evtType ) ;
evt . SetClientData ( clientData ) ;
evt . SetInt ( intParam ) ;
evt . SetExtraLong ( longParam ) ;
evt . SetString ( stringParam ) ;
AddPendingEvent ( evt ) ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : PostCommand ( int evtType , int intParam , long longParam , const wxString & stringParam )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
PostCommand ( NULL , evtType , intParam , longParam , stringParam ) ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
sptr wxAppWithHelpers : : ProcessCommand ( void * clientData , int evtType , int intParam , long longParam , const wxString & stringParam )
2010-01-22 15:22:01 +00:00
{
2016-11-12 15:28:37 +00:00
SynchronousActionState sync ;
pxSynchronousCommandEvent evt ( sync , evtType ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
evt . SetClientData ( clientData ) ;
evt . SetInt ( intParam ) ;
evt . SetExtraLong ( longParam ) ;
evt . SetString ( stringParam ) ;
AddPendingEvent ( evt ) ;
sync . WaitForResult ( ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
return sync . return_value ;
2010-01-22 15:22:01 +00:00
}
2010-01-08 07:11:33 +00:00
2016-11-12 15:28:37 +00:00
sptr wxAppWithHelpers : : ProcessCommand ( int evtType , int intParam , long longParam , const wxString & stringParam )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
return ProcessCommand ( NULL , evtType , intParam , longParam , stringParam ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : PostAction ( const pxActionEvent & evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
PostEvent ( evt ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : ProcessAction ( pxActionEvent & evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
if ( ! wxThread : : IsMain ( ) ) {
SynchronousActionState sync ;
evt . SetSyncState ( sync ) ;
AddPendingEvent ( evt ) ;
sync . WaitForResult ( ) ;
} else
evt . _DoInvokeEvent ( ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : DeleteObject ( BaseDeletableObject & obj )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
pxAssert ( ! obj . IsBeingDeleted ( ) ) ;
wxCommandEvent evt ( pxEvt_DeleteObject ) ;
evt . SetClientData ( ( void * ) & obj ) ;
AddIdleEvent ( evt ) ;
2010-04-27 13:12:03 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : DeleteThread ( pxThread & obj )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
pxThreadLog . Write ( obj . GetName ( ) , L " Scheduling for deletion... " ) ;
wxCommandEvent evt ( pxEvt_DeleteThread ) ;
evt . SetClientData ( ( void * ) & obj ) ;
AddIdleEvent ( evt ) ;
2010-04-27 13:12:03 +00:00
}
2010-01-08 07:11:33 +00:00
bool wxAppWithHelpers : : OnInit ( )
{
2016-11-12 15:28:37 +00:00
Bind ( pxEvt_SynchronousCommand , & wxAppWithHelpers : : OnSynchronousCommand , this ) ;
Bind ( pxEvt_InvokeAction , & wxAppWithHelpers : : OnInvokeAction , this ) ;
2010-01-08 07:11:33 +00:00
2016-11-12 15:28:37 +00:00
Bind ( pxEvt_StartIdleEventTimer , & wxAppWithHelpers : : OnStartIdleEventTimer , this ) ;
2010-01-22 15:22:01 +00:00
2016-11-12 15:28:37 +00:00
Bind ( pxEvt_DeleteObject , & wxAppWithHelpers : : OnDeleteObject , this ) ;
Bind ( pxEvt_DeleteThread , & wxAppWithHelpers : : OnDeleteThread , this ) ;
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
Bind ( wxEVT_IDLE , & wxAppWithHelpers : : OnIdleEvent , this ) ;
2010-01-08 15:51:31 +00:00
2016-11-12 15:28:37 +00:00
Bind ( wxEVT_TIMER , & wxAppWithHelpers : : OnIdleEventTimeout , this , m_IdleEventTimer . GetId ( ) ) ;
2010-01-08 07:11:33 +00:00
2016-11-12 15:28:37 +00:00
return _parent : : OnInit ( ) ;
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : OnInvokeAction ( pxActionEvent & evt )
2010-01-08 07:11:33 +00:00
{
2016-11-12 15:28:37 +00:00
evt . _DoInvokeEvent ( ) ; // wow this is easy!
2010-01-08 07:11:33 +00:00
}
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : OnDeleteObject ( wxCommandEvent & evt )
2010-01-22 15:22:01 +00:00
{
2016-11-12 15:28:37 +00:00
if ( evt . GetClientData ( ) = = NULL )
return ;
delete ( BaseDeletableObject * ) evt . GetClientData ( ) ;
2010-04-27 13:12:03 +00:00
}
2014-11-22 17:51:05 +00:00
// In theory we create a Pcsx2App object which inherit from wxAppWithHelpers,
// so Pcsx2App::CreateTraits must be used instead.
//
// However it doesn't work this way because wxAppWithHelpers constructor will
// be called first. This constructor will build some wx objects (here wxTimer)
// that require a trait. In others word, wxAppWithHelpers::CreateTraits will be
// called instead
2016-11-12 15:28:37 +00:00
wxAppTraits * wxAppWithHelpers : : CreateTraits ( )
2014-11-22 17:51:05 +00:00
{
2016-11-12 15:28:37 +00:00
return new Pcsx2AppTraits ;
2014-11-22 17:51:05 +00:00
}
2010-04-27 13:12:03 +00:00
// Threads have their own deletion handler that propagates exceptions thrown by the thread to the UI.
// (thus we have a fairly automatic threaded exception system!)
2016-11-12 15:28:37 +00:00
void wxAppWithHelpers : : OnDeleteThread ( wxCommandEvent & evt )
2010-04-27 13:12:03 +00:00
{
2016-11-12 15:28:37 +00:00
std : : unique_ptr < pxThread > thr ( ( pxThread * ) evt . GetClientData ( ) ) ;
if ( ! thr ) {
pxThreadLog . Write ( L " null " , L " OnDeleteThread: NULL thread object received (and ignored). " ) ;
return ;
}
2010-04-27 13:12:03 +00:00
2016-11-12 15:28:37 +00:00
pxThreadLog . Write ( thr - > GetName ( ) , wxString ( wxString ( L " Thread object deleted successfully " ) + ( thr - > HasPendingException ( ) ? L " [exception pending!] " : L " " ) ) . wc_str ( ) ) ;
thr - > RethrowException ( ) ;
2010-01-22 15:22:01 +00:00
}
2010-01-08 07:11:33 +00:00
wxAppWithHelpers : : wxAppWithHelpers ( )
2016-11-12 15:28:37 +00:00
: m_IdleEventTimer ( this )
2010-01-08 07:11:33 +00:00
{
# ifdef __WXMSW__
2016-11-12 15:28:37 +00:00
// This variable assignment ensures that MSVC links in the TLS setup stubs even in
// full optimization builds. Without it, DLLs that use TLS won't work because the
// FS segment register won't have been initialized by the main exe, due to tls_insurance
// being optimized away >_< --air
2010-01-08 07:11:33 +00:00
2017-04-13 17:59:00 +00:00
static thread_local int tls_insurance = 0 ;
2016-11-12 15:28:37 +00:00
tls_insurance = 1 ;
2010-01-08 07:11:33 +00:00
# endif
}