/[pcsx2_0.9.7]/trunk/common/src/Utilities/wxAppWithHelpers.cpp
ViewVC logotype

Annotation of /trunk/common/src/Utilities/wxAppWithHelpers.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months ago) by william
File size: 19924 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16     #include "PrecompiledHeader.h"
17     #include "wxAppWithHelpers.h"
18    
19     #include "ThreadingInternal.h"
20     #include "PersistentThread.h"
21    
22     DEFINE_EVENT_TYPE( pxEvt_DeleteObject );
23     DEFINE_EVENT_TYPE( pxEvt_DeleteThread );
24     DEFINE_EVENT_TYPE( pxEvt_StartIdleEventTimer );
25     DEFINE_EVENT_TYPE( pxEvt_InvokeAction );
26     DEFINE_EVENT_TYPE( pxEvt_SynchronousCommand );
27    
28    
29     IMPLEMENT_DYNAMIC_CLASS( pxSimpleEvent, wxEvent )
30    
31 william 62 ConsoleLogSource_App::ConsoleLogSource_App()
32     {
33     static const TraceLogDescriptor myDesc =
34     {
35     L"AppEvents", L"App Events",
36     wxLt("Includes idle event processing and some other uncommon event usages.")
37     };
38    
39     m_Descriptor = &myDesc;
40     }
41 william 31
42 william 62 ConsoleLogSource_App pxConLog_App;
43    
44 william 31 void BaseDeletableObject::DoDeletion()
45     {
46     wxAppWithHelpers* app = wxDynamicCast( wxApp::GetInstance(), wxAppWithHelpers );
47     pxAssume( app != NULL );
48     app->DeleteObject( *this );
49     }
50    
51    
52     // --------------------------------------------------------------------------------------
53     // SynchronousActionState Implementations
54     // --------------------------------------------------------------------------------------
55    
56     void SynchronousActionState::SetException( const BaseException& ex )
57     {
58     m_exception = ex.Clone();
59     }
60    
61     void SynchronousActionState::SetException( BaseException* ex )
62     {
63     if( !m_posted )
64     {
65     m_exception = ex;
66     }
67     else if( wxTheApp )
68     {
69     // transport the exception to the main thread, since the message is fully
70     // asynchronous, or has already entered an asynchronous state. Message is sent
71     // as a non-blocking action since proper handling of user errors on async messages
72     // is *usually* to log/ignore it (hah), or to suspend emulation and issue a dialog
73     // box to the user.
74    
75     pxExceptionEvent ev( ex );
76     wxTheApp->AddPendingEvent( ev );
77     }
78     }
79    
80     void SynchronousActionState::RethrowException() const
81     {
82     if( m_exception ) m_exception->Rethrow();
83     }
84    
85     int SynchronousActionState::WaitForResult()
86     {
87     m_sema.WaitNoCancel();
88     RethrowException();
89     return return_value;
90     }
91    
92     int SynchronousActionState::WaitForResult_NoExceptions()
93     {
94     m_sema.WaitNoCancel();
95     return return_value;
96     }
97    
98     void SynchronousActionState::PostResult( int res )
99     {
100     return_value = res;
101     PostResult();
102     }
103    
104     void SynchronousActionState::ClearResult()
105     {
106     m_posted = false;
107     m_exception = NULL;
108     }
109    
110     void SynchronousActionState::PostResult()
111     {
112     if( m_posted ) return;
113     m_posted = true;
114     m_sema.Post();
115     }
116    
117     // --------------------------------------------------------------------------------------
118 william 62 // pxActionEvent Implementations
119 william 31 // --------------------------------------------------------------------------------------
120    
121 william 62 IMPLEMENT_DYNAMIC_CLASS( pxActionEvent, wxEvent )
122 william 31
123 william 62 pxActionEvent::pxActionEvent( SynchronousActionState* sema, int msgtype )
124 william 31 : wxEvent( 0, msgtype )
125     {
126     m_state = sema;
127     }
128    
129 william 62 pxActionEvent::pxActionEvent( SynchronousActionState& sema, int msgtype )
130 william 31 : wxEvent( 0, msgtype )
131     {
132     m_state = &sema;
133     }
134    
135 william 62 pxActionEvent::pxActionEvent( const pxActionEvent& src )
136 william 31 : wxEvent( src )
137     {
138     m_state = src.m_state;
139     }
140    
141 william 62 void pxActionEvent::SetException( const BaseException& ex )
142 william 31 {
143     SetException( ex.Clone() );
144     }
145    
146 william 62 void pxActionEvent::SetException( BaseException* ex )
147 william 31 {
148     const wxString& prefix( wxsFormat(L"(%s) ", GetClassInfo()->GetClassName()) );
149     ex->DiagMsg() = prefix + ex->DiagMsg();
150    
151     if( !m_state )
152     {
153     ScopedPtr<BaseException> exptr( ex ); // auto-delete it after handling.
154     ex->Rethrow();
155     }
156    
157     m_state->SetException( ex );
158     }
159    
160     // --------------------------------------------------------------------------------------
161     // pxSynchronousCommandEvent
162     // --------------------------------------------------------------------------------------
163     IMPLEMENT_DYNAMIC_CLASS( pxSynchronousCommandEvent, wxCommandEvent )
164    
165     pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, wxEventType commandType, int winid)
166     : wxCommandEvent( pxEvt_SynchronousCommand, winid )
167     {
168     m_sync = sema;
169     m_realEvent = commandType;
170     }
171    
172     pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, wxEventType commandType, int winid)
173     : wxCommandEvent( pxEvt_SynchronousCommand )
174     {
175     m_sync = &sema;
176     m_realEvent = commandType;
177     }
178    
179     pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState* sema, const wxCommandEvent& evt )
180     : wxCommandEvent( evt )
181     {
182     m_sync = sema;
183     m_realEvent = evt.GetEventType();
184     SetEventType( pxEvt_SynchronousCommand );
185     }
186    
187     pxSynchronousCommandEvent::pxSynchronousCommandEvent(SynchronousActionState& sema, const wxCommandEvent& evt )
188     : wxCommandEvent( evt )
189     {
190     m_sync = &sema;
191     m_realEvent = evt.GetEventType();
192     SetEventType( pxEvt_SynchronousCommand );
193     }
194    
195     pxSynchronousCommandEvent::pxSynchronousCommandEvent( const pxSynchronousCommandEvent& src )
196     : wxCommandEvent( src )
197     {
198     m_sync = src.m_sync;
199     m_realEvent = src.m_realEvent;
200     }
201    
202     void pxSynchronousCommandEvent::SetException( const BaseException& ex )
203     {
204     if( !m_sync ) ex.Rethrow();
205     m_sync->SetException( ex );
206     }
207    
208     void pxSynchronousCommandEvent::SetException( BaseException* ex )
209     {
210     if( !m_sync )
211     {
212     ScopedPtr<BaseException> exptr( ex ); // auto-delete it after handling.
213     ex->Rethrow();
214     }
215    
216     m_sync->SetException( ex );
217     }
218    
219     // --------------------------------------------------------------------------------------
220 william 62 // pxRpcEvent
221 william 31 // --------------------------------------------------------------------------------------
222     // Unlike pxPingEvent, the Semaphore belonging to this event is typically posted when the
223     // invoked method is completed. If the method can be executed in non-blocking fashion then
224     // it should leave the semaphore postback NULL.
225     //
226 william 62 class pxRpcEvent : public pxActionEvent
227 william 31 {
228 william 62 DECLARE_DYNAMIC_CLASS_NO_ASSIGN(pxRpcEvent)
229 william 31
230 william 62 typedef pxActionEvent _parent;
231 william 31
232     protected:
233     void (*m_Method)();
234    
235     public:
236 william 62 virtual ~pxRpcEvent() throw() { }
237     virtual pxRpcEvent *Clone() const { return new pxRpcEvent(*this); }
238 william 31
239 william 62 explicit pxRpcEvent( void (*method)()=NULL, SynchronousActionState* sema=NULL )
240     : pxActionEvent( sema )
241 william 31 {
242     m_Method = method;
243     }
244    
245 william 62 explicit pxRpcEvent( void (*method)(), SynchronousActionState& sema )
246     : pxActionEvent( sema )
247 william 31 {
248     m_Method = method;
249     }
250    
251 william 62 pxRpcEvent( const pxRpcEvent& src )
252     : pxActionEvent( src )
253 william 31 {
254     m_Method = src.m_Method;
255     }
256    
257     void SetMethod( void (*method)() )
258     {
259     m_Method = method;
260     }
261    
262     protected:
263     void InvokeEvent()
264     {
265     if( m_Method ) m_Method();
266     }
267     };
268    
269 william 62 IMPLEMENT_DYNAMIC_CLASS( pxRpcEvent, pxActionEvent )
270 william 31
271     // --------------------------------------------------------------------------------------
272     // pxExceptionEvent implementations
273     // --------------------------------------------------------------------------------------
274     pxExceptionEvent::pxExceptionEvent( const BaseException& ex )
275     {
276     m_except = ex.Clone();
277     }
278    
279     void pxExceptionEvent::InvokeEvent()
280     {
281     ScopedPtr<BaseException> deleteMe( m_except );
282     if( deleteMe ) deleteMe->Rethrow();
283     }
284    
285     // --------------------------------------------------------------------------------------
286     // wxAppWithHelpers Implementation
287     // --------------------------------------------------------------------------------------
288     //
289     // TODO : Ping dispatch and IdleEvent dispatch can be unified into a single dispatch, which
290     // would mean checking only one list of events per idle event, instead of two. (ie, ping
291     // events can be appended to the idle event list, instead of into their own custom list).
292     //
293     IMPLEMENT_DYNAMIC_CLASS( wxAppWithHelpers, wxApp )
294    
295    
296     // Posts a method to the main thread; non-blocking. Post occurs even when called from the
297     // main thread.
298     void wxAppWithHelpers::PostMethod( FnType_Void* method )
299     {
300 william 62 PostEvent( pxRpcEvent( method ) );
301 william 31 }
302    
303     // Posts a method to the main thread; non-blocking. Post occurs even when called from the
304     // main thread.
305     void wxAppWithHelpers::PostIdleMethod( FnType_Void* method )
306     {
307 william 62 pxRpcEvent evt( method );
308 william 31 AddIdleEvent( evt );
309     }
310    
311 william 62 // Invokes the specified void method, or posts the method to the main thread if the calling
312     // thread is not Main. Action is blocking. For non-blocking method execution, use
313     // AppRpc_TryInvokeAsync.
314     //
315     // This function works something like setjmp/longjmp, in that the return value indicates if the
316     // function actually executed the specified method or not.
317     //
318     // Returns:
319     // FALSE if the method was not invoked (meaning this IS the main thread!)
320     // TRUE if the method was invoked.
321     //
322    
323     bool wxAppWithHelpers::Rpc_TryInvoke( FnType_Void* method )
324 william 31 {
325     if( wxThread::IsMain() ) return false;
326 william 62
327     SynchronousActionState sync;
328     PostEvent( pxRpcEvent( method, sync ) );
329     sync.WaitForResult();
330    
331 william 31 return true;
332     }
333    
334 william 62 // Invokes the specified void method, or posts the method to the main thread if the calling
335     // thread is not Main. Action is non-blocking (asynchronous). For blocking method execution,
336     // use AppRpc_TryInvoke.
337     //
338     // This function works something like setjmp/longjmp, in that the return value indicates if the
339     // function actually executed the specified method or not.
340     //
341     // Returns:
342     // FALSE if the method was not posted to the main thread (meaning this IS the main thread!)
343     // TRUE if the method was posted.
344     //
345     bool wxAppWithHelpers::Rpc_TryInvokeAsync( FnType_Void* method )
346 william 31 {
347 william 62 if( wxThread::IsMain() ) return false;
348     PostEvent( pxRpcEvent( method ) );
349     return true;
350     }
351    
352     void wxAppWithHelpers::ProcessMethod( FnType_Void* method )
353     {
354 william 31 if( wxThread::IsMain() )
355     {
356     method();
357     return;
358     }
359    
360     SynchronousActionState sync;
361 william 62 PostEvent( pxRpcEvent( method, sync ) );
362 william 31 sync.WaitForResult();
363     }
364    
365     void wxAppWithHelpers::PostEvent( const wxEvent& evt )
366     {
367     // Const Cast is OK!
368     // Truth is, AddPendingEvent should be a const-qualified parameter, as
369     // it makes an immediate clone copy of the event -- but wxWidgets
370     // fails again in structured C/C++ design design. So I'm forcing it as such
371     // here. -- air
372    
373     _parent::AddPendingEvent( const_cast<wxEvent&>(evt) );
374     }
375    
376     bool wxAppWithHelpers::ProcessEvent( wxEvent& evt )
377     {
378     // Note: We can't do an automatic blocking post of the message here, because wxWidgets
379     // isn't really designed for it (some events return data to the caller via the event
380     // struct, and posting the event would require a temporary clone, where changes would
381     // be lost).
382    
383     AffinityAssert_AllowFrom_MainUI();
384     return _parent::ProcessEvent( evt );
385     }
386    
387     bool wxAppWithHelpers::ProcessEvent( wxEvent* evt )
388     {
389     AffinityAssert_AllowFrom_MainUI();
390     ScopedPtr<wxEvent> deleteMe( evt );
391     return _parent::ProcessEvent( *deleteMe );
392     }
393    
394 william 62 bool wxAppWithHelpers::ProcessEvent( pxActionEvent& evt )
395 william 31 {
396     if( wxThread::IsMain() )
397     return _parent::ProcessEvent( evt );
398     else
399     {
400     SynchronousActionState sync;
401     evt.SetSyncState( sync );
402     AddPendingEvent( evt );
403     sync.WaitForResult();
404     return true;
405     }
406     }
407    
408 william 62 bool wxAppWithHelpers::ProcessEvent( pxActionEvent* evt )
409 william 31 {
410     if( wxThread::IsMain() )
411     {
412     ScopedPtr<wxEvent> deleteMe( evt );
413     return _parent::ProcessEvent( *deleteMe );
414     }
415     else
416     {
417     SynchronousActionState sync;
418     evt->SetSyncState( sync );
419     AddPendingEvent( *evt );
420     sync.WaitForResult();
421     return true;
422     }
423     }
424    
425    
426     void wxAppWithHelpers::CleanUp()
427     {
428     // I'm pretty sure the message pump is dead by now, which means we need to run through
429     // idle event list by hand and process the pending Deletion messages (all others can be
430     // ignored -- it's only deletions we want handled, and really we *could* ignore those too
431     // but I like to be tidy. -- air
432    
433     //IdleEventDispatcher( "CleanUp" );
434     //DeletionDispatcher();
435     _parent::CleanUp();
436     }
437    
438 william 62 // Executes the event with exception handling. If the event throws an exception, the exception
439     // will be neatly packaged and transported back to the thread that posted the event.
440     // This function is virtual, however overloading it is not recommended. Derrived classes
441     // should overload InvokeEvent() instead.
442     void pxActionEvent::_DoInvokeEvent()
443 william 31 {
444     AffinityAssert_AllowFrom_MainUI();
445    
446     try {
447     InvokeEvent();
448     }
449     catch( BaseException& ex )
450     {
451     SetException( ex );
452     }
453     catch( std::runtime_error& ex )
454     {
455     SetException( new Exception::RuntimeError( ex ) );
456     }
457    
458     if( m_state ) m_state->PostResult();
459     }
460    
461     void wxAppWithHelpers::OnSynchronousCommand( pxSynchronousCommandEvent& evt )
462     {
463     AffinityAssert_AllowFrom_MainUI();
464    
465 william 62 pxAppLog.Write(L"(App) Executing command event synchronously...");
466 william 31 evt.SetEventType( evt.GetRealEventType() );
467    
468     try {
469     ProcessEvent( evt );
470     }
471     catch( BaseException& ex )
472     {
473     evt.SetException( ex );
474     }
475     catch( std::runtime_error& ex )
476     {
477     evt.SetException( new Exception::RuntimeError( ex, evt.GetClassInfo()->GetClassName() ) );
478     }
479    
480     if( Semaphore* sema = evt.GetSemaphore() ) sema->Post();
481     }
482    
483     void wxAppWithHelpers::AddIdleEvent( const wxEvent& evt )
484     {
485     ScopedLock lock( m_IdleEventMutex );
486     if( m_IdleEventQueue.size() == 0 )
487     PostEvent( pxSimpleEvent( pxEvt_StartIdleEventTimer ) );
488    
489     m_IdleEventQueue.push_back( evt.Clone() );
490     }
491    
492     void wxAppWithHelpers::OnStartIdleEventTimer( wxEvent& evt )
493     {
494     ScopedLock lock( m_IdleEventMutex );
495     if( m_IdleEventQueue.size() != 0 )
496     m_IdleEventTimer.Start( 100, true );
497     }
498    
499     void wxAppWithHelpers::IdleEventDispatcher( const wxChar* action )
500     {
501     // Recursion is possible thanks to modal dialogs being issued from the idle event handler.
502     // (recursion shouldn't hurt anything anyway, since the node system re-creates the iterator
503     // on each pass)
504    
505     //static int __guard=0;
506     //RecursionGuard guard(__guard);
507     //if( !pxAssertDev(!guard.IsReentrant(), "Re-entrant call to IdleEventdispatcher caught on camera!") ) return;
508    
509     wxEventList postponed;
510     wxEventList::iterator node;
511    
512     ScopedLock lock( m_IdleEventMutex );
513    
514     while( node = m_IdleEventQueue.begin(), node != m_IdleEventQueue.end() )
515     {
516     ScopedPtr<wxEvent> deleteMe(*node);
517     m_IdleEventQueue.erase( node );
518    
519     lock.Release();
520     if( !Threading::AllowDeletions() && (deleteMe->GetEventType() == pxEvt_DeleteThread) )
521     {
522 william 62 // Threads that have active semaphores or mutexes (other threads are waiting on them) cannot
523     // be deleted because those mutex/sema objects will become invalid and cause the pending
524     // thread to crash. So we disallow deletions when those waits are in action, and continue
525     // to postpone the deletion of the thread until such time that it is safe.
526    
527     pxThreadLog.Write( ((pxThread*)((wxCommandEvent*)deleteMe.GetPtr())->GetClientData())->GetName(), L"Deletion postponed due to mutex or semaphore dependency." );
528 william 31 postponed.push_back(deleteMe.DetachPtr());
529     }
530     else
531     {
532 william 62 pxAppLog.Write( L"(AppIdleQueue%s) Dispatching event '%s'", action, deleteMe->GetClassInfo()->GetClassName() );
533 william 31 ProcessEvent( *deleteMe ); // dereference to prevent auto-deletion by ProcessEvent
534     }
535     lock.Acquire();
536     }
537    
538     m_IdleEventQueue = postponed;
539 william 62 if( m_IdleEventQueue.size() > 0 )
540     pxAppLog.Write( L"(AppIdleQueue%s) %d events postponed due to dependencies.", action, m_IdleEventQueue.size() );
541 william 31 }
542    
543     void wxAppWithHelpers::OnIdleEvent( wxIdleEvent& evt )
544     {
545     m_IdleEventTimer.Stop();
546 william 62 IdleEventDispatcher();
547 william 31 }
548    
549     void wxAppWithHelpers::OnIdleEventTimeout( wxTimerEvent& evt )
550     {
551 william 62 IdleEventDispatcher( L"[Timeout]" );
552 william 31 }
553    
554     void wxAppWithHelpers::Ping()
555     {
556 william 62 pxThreadLog.Write( pxGetCurrentThreadName().c_str(), L"App Event Ping Requested." );
557 william 31
558     SynchronousActionState sync;
559 william 62 pxActionEvent evt( sync );
560 william 31 AddIdleEvent( evt );
561     sync.WaitForResult();
562     }
563    
564     void wxAppWithHelpers::PostCommand( void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam )
565     {
566     wxCommandEvent evt( evtType );
567     evt.SetClientData( clientData );
568     evt.SetInt( intParam );
569     evt.SetExtraLong( longParam );
570     evt.SetString( stringParam );
571     AddPendingEvent( evt );
572     }
573    
574     void wxAppWithHelpers::PostCommand( int evtType, int intParam, long longParam, const wxString& stringParam )
575     {
576     PostCommand( NULL, evtType, intParam, longParam, stringParam );
577     }
578    
579     sptr wxAppWithHelpers::ProcessCommand( void* clientData, int evtType, int intParam, long longParam, const wxString& stringParam )
580     {
581     SynchronousActionState sync;
582     pxSynchronousCommandEvent evt( sync, evtType );
583    
584     evt.SetClientData( clientData );
585     evt.SetInt( intParam );
586     evt.SetExtraLong( longParam );
587     evt.SetString( stringParam );
588     AddPendingEvent( evt );
589     sync.WaitForResult();
590    
591     return sync.return_value;
592     }
593    
594     sptr wxAppWithHelpers::ProcessCommand( int evtType, int intParam, long longParam, const wxString& stringParam )
595     {
596     return ProcessCommand( NULL, evtType, intParam, longParam, stringParam );
597     }
598    
599 william 62 void wxAppWithHelpers::PostAction( const pxActionEvent& evt )
600 william 31 {
601     PostEvent( evt );
602     }
603    
604 william 62 void wxAppWithHelpers::ProcessAction( pxActionEvent& evt )
605 william 31 {
606     if( !wxThread::IsMain() )
607     {
608     SynchronousActionState sync;
609     evt.SetSyncState( sync );
610     AddPendingEvent( evt );
611     sync.WaitForResult();
612     }
613     else
614     evt._DoInvokeEvent();
615     }
616    
617    
618     void wxAppWithHelpers::DeleteObject( BaseDeletableObject& obj )
619     {
620 william 62 pxAssert( !obj.IsBeingDeleted() );
621 william 31 wxCommandEvent evt( pxEvt_DeleteObject );
622     evt.SetClientData( (void*)&obj );
623     AddIdleEvent( evt );
624     }
625    
626 william 62 void wxAppWithHelpers::DeleteThread( pxThread& obj )
627 william 31 {
628 william 62 pxThreadLog.Write(obj.GetName(), L"Scheduling for deletion...");
629 william 31 wxCommandEvent evt( pxEvt_DeleteThread );
630     evt.SetClientData( (void*)&obj );
631     AddIdleEvent( evt );
632     }
633    
634 william 62 typedef void (wxEvtHandler::*pxInvokeActionEventFunction)(pxActionEvent&);
635 william 31
636     bool wxAppWithHelpers::OnInit()
637     {
638     #define pxActionEventHandler(func) \
639     (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(pxInvokeActionEventFunction, &func )
640    
641     Connect( pxEvt_SynchronousCommand, pxSynchronousEventHandler (wxAppWithHelpers::OnSynchronousCommand) );
642     Connect( pxEvt_InvokeAction, pxActionEventHandler (wxAppWithHelpers::OnInvokeAction) );
643    
644     Connect( pxEvt_StartIdleEventTimer, wxEventHandler (wxAppWithHelpers::OnStartIdleEventTimer) );
645    
646     Connect( pxEvt_DeleteObject, wxCommandEventHandler (wxAppWithHelpers::OnDeleteObject) );
647     Connect( pxEvt_DeleteThread, wxCommandEventHandler (wxAppWithHelpers::OnDeleteThread) );
648    
649     Connect( wxEVT_IDLE, wxIdleEventHandler (wxAppWithHelpers::OnIdleEvent) );
650    
651     Connect( m_IdleEventTimer.GetId(), wxEVT_TIMER, wxTimerEventHandler(wxAppWithHelpers::OnIdleEventTimeout) );
652    
653     return _parent::OnInit();
654     }
655    
656 william 62 void wxAppWithHelpers::OnInvokeAction( pxActionEvent& evt )
657 william 31 {
658     evt._DoInvokeEvent(); // wow this is easy!
659     }
660    
661     void wxAppWithHelpers::OnDeleteObject( wxCommandEvent& evt )
662     {
663     if( evt.GetClientData() == NULL ) return;
664     delete (BaseDeletableObject*)evt.GetClientData();
665     }
666    
667     // Threads have their own deletion handler that propagates exceptions thrown by the thread to the UI.
668     // (thus we have a fairly automatic threaded exception system!)
669     void wxAppWithHelpers::OnDeleteThread( wxCommandEvent& evt )
670     {
671 william 62 ScopedPtr<pxThread> thr( (pxThread*)evt.GetClientData() );
672     if( !thr )
673     {
674     pxThreadLog.Write( L"null", L"OnDeleteThread: NULL thread object received (and ignored)." );
675     return;
676     }
677 william 31
678 william 62 pxThreadLog.Write(thr->GetName(), (wxString)L"Thread object deleted successfully" + (thr->HasPendingException() ? wxEmptyString : L"[exception pending!]"));
679 william 31 thr->RethrowException();
680     }
681    
682     wxAppWithHelpers::wxAppWithHelpers()
683     : m_IdleEventTimer( this )
684     {
685     #ifdef __WXMSW__
686     // This variable assignment ensures that MSVC links in the TLS setup stubs even in
687     // full optimization builds. Without it, DLLs that use TLS won't work because the
688     // FS segment register won't have been initialized by the main exe, due to tls_insurance
689     // being optimized away >_< --air
690    
691     static __threadlocal int tls_insurance = 0;
692     tls_insurance = 1;
693     #endif
694     }
695    

  ViewVC Help
Powered by ViewVC 1.1.22