2010-01-08 07:11:33 +00:00
|
|
|
/* 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 "wxAppWithHelpers.h"
|
|
|
|
|
|
|
|
DEFINE_EVENT_TYPE( pxEvt_Ping );
|
2010-03-05 14:24:44 +00:00
|
|
|
DEFINE_EVENT_TYPE( pxEvt_IdleEventQueue );
|
2010-01-08 07:11:33 +00:00
|
|
|
DEFINE_EVENT_TYPE( pxEvt_MessageBox );
|
2010-01-22 15:22:01 +00:00
|
|
|
DEFINE_EVENT_TYPE( pxEvt_DeleteObject );
|
|
|
|
//DEFINE_EVENT_TYPE( pxEvt_Assertion );
|
|
|
|
|
|
|
|
|
|
|
|
void IDeletableObject::DoDeletion()
|
|
|
|
{
|
|
|
|
wxAppWithHelpers* app = wxDynamicCast( wxApp::GetInstance(), wxAppWithHelpers );
|
|
|
|
pxAssume( app != NULL );
|
|
|
|
app->DeleteObject( *this );
|
|
|
|
}
|
2010-01-08 07:11:33 +00:00
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
// pxPingEvent Implementations
|
|
|
|
// --------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS( pxPingEvent, wxEvent )
|
|
|
|
|
|
|
|
pxPingEvent::pxPingEvent( int msgtype, Semaphore* sema )
|
|
|
|
: wxEvent( 0, msgtype )
|
|
|
|
{
|
|
|
|
m_PostBack = sema;
|
|
|
|
}
|
|
|
|
|
|
|
|
pxPingEvent::pxPingEvent( Semaphore* sema )
|
|
|
|
: wxEvent( 0, pxEvt_Ping )
|
|
|
|
{
|
|
|
|
m_PostBack = sema;
|
|
|
|
}
|
|
|
|
|
|
|
|
pxPingEvent::pxPingEvent( const pxPingEvent& src )
|
|
|
|
: wxEvent( src )
|
|
|
|
{
|
|
|
|
m_PostBack = src.m_PostBack;
|
|
|
|
}
|
|
|
|
|
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).
|
|
|
|
//
|
2010-01-22 15:22:01 +00:00
|
|
|
IMPLEMENT_DYNAMIC_CLASS( wxAppWithHelpers, wxApp )
|
|
|
|
|
2010-03-05 14:24:44 +00:00
|
|
|
void wxAppWithHelpers::CleanUp()
|
|
|
|
{
|
|
|
|
DeletionDispatcher();
|
|
|
|
_parent::CleanUp();
|
|
|
|
}
|
|
|
|
|
2010-01-08 07:11:33 +00:00
|
|
|
void wxAppWithHelpers::OnPingEvent( pxPingEvent& evt )
|
|
|
|
{
|
|
|
|
// Ping events are dispatched during the idle event handler, which ensures
|
|
|
|
// the ping is posted only after all other pending messages behind the ping
|
|
|
|
// are also processed.
|
|
|
|
|
2010-03-05 14:24:44 +00:00
|
|
|
if( m_PingWhenIdle.size() == 0 ) m_PingTimer.Start( 200, true );
|
2010-01-08 07:11:33 +00:00
|
|
|
m_PingWhenIdle.push_back( evt.GetSemaphore() );
|
|
|
|
}
|
|
|
|
|
2010-03-05 14:24:44 +00:00
|
|
|
void wxAppWithHelpers::OnAddEventToIdleQueue( wxEvent& evt )
|
2010-01-22 15:22:01 +00:00
|
|
|
{
|
2010-03-05 14:24:44 +00:00
|
|
|
if( m_IdleEventQueue.size() == 0 ) m_IdleEventTimer.Start( 100, true );
|
|
|
|
m_IdleEventQueue.push_back( evt.Clone() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void wxAppWithHelpers::IdleEventDispatcher( const char* action )
|
|
|
|
{
|
|
|
|
size_t size = m_IdleEventQueue.size();
|
|
|
|
if( size == 0 ) return;
|
|
|
|
|
|
|
|
DbgCon.WriteLn( Color_Gray, "App IdleQueue (%s) -> %u events.", action, size );
|
|
|
|
|
|
|
|
for( size_t i=0; i<size; ++i )
|
|
|
|
{
|
|
|
|
ProcessEvent( *m_IdleEventQueue[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_IdleEventQueue.clear();
|
2010-01-22 15:22:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void wxAppWithHelpers::PingDispatcher( const char* action )
|
2010-01-08 07:11:33 +00:00
|
|
|
{
|
|
|
|
size_t size = m_PingWhenIdle.size();
|
|
|
|
if( size == 0 ) return;
|
|
|
|
|
|
|
|
DbgCon.WriteLn( Color_Gray, "App Event Ping (%s) -> %u listeners.", action, size );
|
|
|
|
|
|
|
|
for( size_t i=0; i<size; ++i )
|
|
|
|
{
|
|
|
|
if( Semaphore* sema = m_PingWhenIdle[i] ) sema->Post();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_PingWhenIdle.clear();
|
|
|
|
}
|
|
|
|
|
2010-01-22 15:22:01 +00:00
|
|
|
void wxAppWithHelpers::DeletionDispatcher()
|
|
|
|
{
|
|
|
|
ScopedLock lock( m_DeleteIdleLock );
|
|
|
|
|
|
|
|
size_t size = m_DeleteWhenIdle.size();
|
|
|
|
if( size == 0 ) return;
|
|
|
|
|
|
|
|
DbgCon.WriteLn( Color_Gray, "App Idle Delete -> %u objects.", size );
|
|
|
|
}
|
|
|
|
|
2010-01-08 07:11:33 +00:00
|
|
|
void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt )
|
|
|
|
{
|
|
|
|
m_PingTimer.Stop();
|
2010-03-05 14:24:44 +00:00
|
|
|
m_IdleEventTimer.Stop();
|
2010-01-22 15:22:01 +00:00
|
|
|
PingDispatcher( "Idle" );
|
2010-03-05 14:24:44 +00:00
|
|
|
IdleEventDispatcher( "Idle" );
|
2010-01-08 07:11:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void wxAppWithHelpers::OnPingTimeout( wxTimerEvent& evt )
|
|
|
|
{
|
2010-01-22 15:22:01 +00:00
|
|
|
PingDispatcher( "Timeout" );
|
2010-01-08 07:11:33 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 14:24:44 +00:00
|
|
|
void wxAppWithHelpers::OnIdleEventTimeout( wxTimerEvent& evt )
|
|
|
|
{
|
|
|
|
IdleEventDispatcher( "Timeout" );
|
|
|
|
}
|
|
|
|
|
2010-01-08 07:11:33 +00:00
|
|
|
void wxAppWithHelpers::Ping()
|
|
|
|
{
|
|
|
|
DbgCon.WriteLn( Color_Gray, L"App Event Ping Requested from %s thread.", pxGetCurrentThreadName().c_str() );
|
|
|
|
|
|
|
|
Semaphore sema;
|
|
|
|
pxPingEvent evt( &sema );
|
|
|
|
AddPendingEvent( evt );
|
|
|
|
sema.WaitNoCancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void wxAppWithHelpers::PostCommand( void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam )
|
|
|
|
{
|
|
|
|
wxCommandEvent evt( evtType );
|
|
|
|
evt.SetClientData( clientData );
|
|
|
|
evt.SetInt( intParam );
|
|
|
|
evt.SetExtraLong( longParam );
|
|
|
|
evt.SetString( stringParam );
|
|
|
|
AddPendingEvent( evt );
|
|
|
|
}
|
|
|
|
|
|
|
|
void wxAppWithHelpers::PostCommand( int evtType, int intParam, long longParam, const wxString& stringParam )
|
|
|
|
{
|
|
|
|
PostCommand( NULL, evtType, intParam, longParam, stringParam );
|
|
|
|
}
|
|
|
|
|
2010-01-22 15:22:01 +00:00
|
|
|
void wxAppWithHelpers::DeleteObject( IDeletableObject& obj )
|
|
|
|
{
|
|
|
|
pxAssume( obj.IsBeingDeleted() );
|
|
|
|
ScopedLock lock( m_DeleteIdleLock );
|
|
|
|
m_DeleteWhenIdle.push_back( &obj );
|
|
|
|
}
|
2010-01-08 07:11:33 +00:00
|
|
|
|
2010-01-22 15:22:01 +00:00
|
|
|
typedef void (wxEvtHandler::*BaseMessageBoxEventFunction)(BaseMessageBoxEvent&);
|
2010-01-08 07:11:33 +00:00
|
|
|
typedef void (wxEvtHandler::*pxPingEventFunction)(pxPingEvent&);
|
|
|
|
|
|
|
|
bool wxAppWithHelpers::OnInit()
|
|
|
|
{
|
|
|
|
#define pxMessageBoxEventThing(func) \
|
2010-01-22 15:22:01 +00:00
|
|
|
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(BaseMessageBoxEventFunction, &func )
|
2010-01-08 07:11:33 +00:00
|
|
|
|
|
|
|
#define pxPingEventHandler(func) \
|
|
|
|
(wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxPingEventFunction, &func )
|
|
|
|
|
2010-01-22 15:22:01 +00:00
|
|
|
|
2010-01-08 07:11:33 +00:00
|
|
|
Connect( pxEvt_MessageBox, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) );
|
2010-01-22 15:22:01 +00:00
|
|
|
//Connect( pxEvt_Assertion, pxMessageBoxEventThing (wxAppWithHelpers::OnMessageBox) );
|
2010-01-08 07:11:33 +00:00
|
|
|
Connect( pxEvt_Ping, pxPingEventHandler (wxAppWithHelpers::OnPingEvent) );
|
2010-03-05 14:24:44 +00:00
|
|
|
Connect( pxEvt_IdleEventQueue, wxEventHandler (wxAppWithHelpers::OnAddEventToIdleQueue) );
|
2010-01-22 15:22:01 +00:00
|
|
|
Connect( pxEvt_DeleteObject, wxCommandEventHandler (wxAppWithHelpers::OnDeleteObject) );
|
2010-01-08 08:09:10 +00:00
|
|
|
Connect( wxEVT_IDLE, wxIdleEventHandler (wxAppWithHelpers::OnIdleEvent) );
|
2010-01-08 15:51:31 +00:00
|
|
|
|
2010-03-05 14:24:44 +00:00
|
|
|
Connect( m_PingTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnPingTimeout) );
|
|
|
|
Connect( m_IdleEventTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnIdleEventTimeout) );
|
2010-01-08 07:11:33 +00:00
|
|
|
|
|
|
|
return _parent::OnInit();
|
|
|
|
}
|
|
|
|
|
2010-01-22 15:22:01 +00:00
|
|
|
void wxAppWithHelpers::OnMessageBox( BaseMessageBoxEvent& evt )
|
2010-01-08 07:11:33 +00:00
|
|
|
{
|
|
|
|
evt.IssueDialog();
|
|
|
|
}
|
|
|
|
|
2010-01-22 15:22:01 +00:00
|
|
|
void wxAppWithHelpers::OnDeleteObject( wxCommandEvent& evt )
|
|
|
|
{
|
|
|
|
if( evt.GetClientData() == NULL ) return;
|
|
|
|
delete (IDeletableObject*)evt.GetClientData();
|
|
|
|
}
|
|
|
|
|
2010-01-08 07:11:33 +00:00
|
|
|
wxAppWithHelpers::wxAppWithHelpers()
|
|
|
|
: m_PingTimer( this )
|
2010-03-05 14:24:44 +00:00
|
|
|
, m_IdleEventTimer( this )
|
2010-01-08 07:11:33 +00:00
|
|
|
{
|
|
|
|
#ifdef __WXMSW__
|
|
|
|
// 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
|
|
|
|
|
|
|
|
static __threadlocal int tls_insurance = 0;
|
|
|
|
tls_insurance = 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|