//========== Copyright (c) Valve Corporation, All rights reserved. ==========// // // Purpose: // // $NoKeywords: $ // //===========================================================================// #ifndef IEVENTSYSTEM_H #define IEVENTSYSTEM_H #ifdef _WIN32 #pragma once #endif #include "appframework/iappsystem.h" #include "tier0/basetypes.h" #include "tier1/functors.h" //----------------------------------------------------------------------------- // Event queues are used to allow listeners to decide at what point they // want to deal with event processing //----------------------------------------------------------------------------- DECLARE_POINTER_HANDLE( EventQueue_t ); #define EVENT_QUEUE_HANDLE_INVALID ( (EventQueue_t)0 ) DECLARE_POINTER_HANDLE( EventId_t ); #define EVENT_ID_INVALID ( (EventId_t)0 ) //----------------------------------------------------------------------------- // Global interface for posting/listening to events // // Usage for registering/unregistering listeners and posting events: // DEFINE_EVENT2_WITHNAMES( TestEvent, int, x, int, y ); // void OnTestEvent( const int &x, const int &y ); // void f() // { // hTest = g_pEventSystem->CreateEventQueue(); // TestEvent::RegisterFunc( hTest, OnTestEvent ); // or TestEvent::RegisterFunc( hTest, myClassPtr, &CMyClass::OnTestEvent ); // TestEvent::Post( 100, 200 ); // TestEvent::PostToListener( myClassPtr, 100, 200 ); // g_pEventSystem->ProcessEvents( hTest ); // TestEvent::UnregisterFunc( hTest, OnTestEvent ); // g_pEventSystem->DestroyEventQueue( hTest ); // } // // Note that the arguments of the event handlers are always const references // to the arguments specified in the event declaration to avoid extra copies // of the data. // // Also note that it's possible to post an event to a specific listener // using PostToListener. Just specify the class name as the first argument. // // Shit gets funky when you pass pointers to events. You need to be very careful // that the pointer is guaranteed to be valid until the messages are being posted. // Also, because everything is a const reference, the function prototypes // for stuff that accepts pointers looks like this strangeness: // // DEFINE_EVENT2_WITHNAMES( TestEvent, int, x, char *, pName ); // void OnTestEvent( const int &x, char * const & pName ); // // Also note: You cannot register or unregister while in the middle of processing events // // NOTE: We use EventClass::RegisterMemberFunc / EventClass:RegisterFunc // instead of overloading EventClass::Register to get more sane-looking // error message from the compiler if it happens to be passed an invalid // event handler. // // From a perf standpoint, registering + unregistering listeners, and // destroying event queues all can cause thread stalls. Do them with // low frequency. //----------------------------------------------------------------------------- abstract_class IEventSystem : public IAppSystem { public: // Creates an event queue. // Creation can occur at any time. Destruction can happen at any time // provided you're not simultaneously processing events or registering/unregistering // listeners on the same thread virtual EventQueue_t CreateEventQueue() = 0; virtual void DestroyEventQueue( EventQueue_t hQueue ) = 0; // Processess queued events for a event queue virtual void ProcessEvents( EventQueue_t hQueue ) = 0; // Ignore that macro magic! It allows us to call PostEvent on an arbitrary event id // with arbitrary arguments. Useful to allow systems to post event ids told to // it by external systems inline void PostEvent( EventId_t nEventId ) { CFunctorData *pData = CreateFunctorData( ); PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, NULL, pData ); } inline void PostEvent( EventId_t nEventId, EventQueue_t hQueue ) { CFunctorData *pData = CreateFunctorData( ); PostEventInternal( nEventId, hQueue, NULL, pData ); } inline void PostEventToListener( EventId_t nEventId, const void *pListener ) { CFunctorData *pData = CreateFunctorData( ); PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, pListener, pData ); } inline void PostEventToListener( EventId_t nEventId, EventQueue_t hQueue, const void *pListener ) { CFunctorData *pData = CreateFunctorData( ); PostEventInternal( nEventId, hQueue, pListener, pData ); } #define DEFINE_POST_EVENT(N) \ template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ inline void PostEvent( EventId_t nEventId FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, NULL, pData ); \ } \ template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ inline void PostEvent( EventId_t nEventId, EventQueue_t hQueue FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ PostEventInternal( nEventId, hQueue, NULL, pData ); \ } \ template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ inline void PostEventToListener( EventId_t nEventId, const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ PostEventInternal( nEventId, EVENT_QUEUE_HANDLE_INVALID, pListener, pData ); \ } \ template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ inline void PostEventToListener( EventId_t nEventId, EventQueue_t hQueue, const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ PostEventInternal( nEventId, hQueue, pListener, pData ); \ } FUNC_GENERATE_ALL_BUT0( DEFINE_POST_EVENT ); #undef DEFINE_POST_EVENT private: // NOTE: These are not meant to be called directly. See the comment above // the IEventSystem class definition for how to post/register/unregister events virtual EventId_t RegisterEvent( const char *pEventName ) = 0; virtual void PostEventInternal( EventId_t nEventId, EventQueue_t hQueue, const void *pListener, CFunctorData *pData ) = 0; virtual void RegisterListener( EventId_t nEventId, EventQueue_t hQueue, CFunctorCallback *pCallback ) = 0; virtual void UnregisterListener( EventId_t nEventId, EventQueue_t hQueue, CFunctorCallback *pCallback ) = 0; #define DEFINE_FRIEND_CLASSES(N) \ template < typename Event_t FUNC_TEMPLATE_ARG_PARAMS_##N > friend class CEventSignature##N FUNC_GENERATE_ALL( DEFINE_FRIEND_CLASSES ); #undef DEFINE_FRIEND_CLASSES }; //----------------------------------------------------------------------------- // Ignore that man behind the curtain! //----------------------------------------------------------------------------- #define DEFINE_EVENT_INTERNAL(N) \ template < typename Event_t FUNC_TEMPLATE_ARG_PARAMS_##N > \ class CEventSignature##N \ { \ public: \ static inline void Post( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ g_pEventSystem->PostEventInternal( Event_t::GetEventId(), EVENT_QUEUE_HANDLE_INVALID, NULL, pData ); \ } \ static inline void Post( EventQueue_t hQueue FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ g_pEventSystem->PostEventInternal( Event_t::GetEventId(), hQueue, NULL, pData ); \ } \ static inline void PostToListener( const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ g_pEventSystem->PostEventInternal( Event_t::GetEventId(), EVENT_QUEUE_HANDLE_INVALID, pListener, pData ); \ } \ static inline void PostToListener( EventQueue_t hQueue, const void *pListener FUNC_ARG_FORMAL_PARAMS_##N ) \ { \ CFunctorData *pData = CreateFunctorData( FUNC_CALL_ARGS_##N ); \ g_pEventSystem->PostEventInternal( Event_t::GetEventId(), hQueue, pListener, pData ); \ } \ static inline void RegisterFunc( EventQueue_t hQueue, void (*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ { \ CFunctorCallback *pCallback = CreateFunctorCallback( pfnProxied ); \ g_pEventSystem->RegisterListener( Event_t::GetEventId(), hQueue, pCallback ); \ } \ static inline void UnregisterFunc( EventQueue_t hQueue, void (*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ { \ CFunctorCallback *pCallback = CreateFunctorCallback( pfnProxied ); \ g_pEventSystem->UnregisterListener( Event_t::GetEventId(), hQueue, pCallback ); \ } \ template < class OBJECT_TYPE_PTR > \ static inline void RegisterMemberFunc( EventQueue_t hQueue, OBJECT_TYPE_PTR *pClass, void (OBJECT_TYPE_PTR::*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ { \ CFunctorCallback *pCallback = CreateFunctorCallback( pClass, pfnProxied ); \ g_pEventSystem->RegisterListener( Event_t::GetEventId(), hQueue, pCallback ); \ } \ template < class OBJECT_TYPE_PTR > \ static inline void UnregisterMemberFunc( EventQueue_t hQueue, OBJECT_TYPE_PTR *pClass, void (OBJECT_TYPE_PTR::*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ { \ CFunctorCallback *pCallback = CreateFunctorCallback( pClass, pfnProxied ); \ g_pEventSystem->UnregisterListener( Event_t::GetEventId(), hQueue, pCallback ); \ } \ static EventId_t RegisterEvent( const char *pEventName ) \ { \ return g_pEventSystem->RegisterEvent( pEventName ); \ } \ }; FUNC_GENERATE_ALL( DEFINE_EVENT_INTERNAL ) #define DEFINE_EVENTID_INTERNAL( _eventName ) \ public: \ static EventId_t GetEventId() \ { \ static EventId_t s_nEventId = EVENT_ID_INVALID; \ if ( s_nEventId == EVENT_ID_INVALID ) \ { \ s_nEventId = RegisterEvent( #_eventName ); \ } \ return s_nEventId; \ } #define DEFINE_EVENT( _eventName ) class _eventName : public CEventSignature0< _eventName > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT1( _eventName, _arg1 ) class _eventName : public CEventSignature1< _eventName, _arg1 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT2( _eventName, _arg1, _arg2 ) class _eventName : public CEventSignature2< _eventName, _arg1, _arg2 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT3( _eventName, _arg1, _arg2, _arg3 ) class _eventName : public CEventSignature3< _eventName, _arg1, _arg2, _arg3 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT4( _eventName, _arg1, _arg2, _arg3, _arg4 ) class _eventName : public CEventSignature4< _eventName, _arg1, _arg2, _arg3, _arg4 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT5( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5 ) class _eventName : public CEventSignature5< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT6( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6 ) class _eventName : public CEventSignature6< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT7( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7 ) class _eventName : public CEventSignature7< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT8( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8 ) class _eventName : public CEventSignature8< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT9( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9 ) class _eventName : public CEventSignature9< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT10( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10 ) class _eventName : public CEventSignature10< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT11( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11 ) class _eventName : public CEventSignature11< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT12( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12 ) class _eventName : public CEventSignature12< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT13( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13 ) class _eventName : public CEventSignature13< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT14( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13, _arg14 ) class _eventName : public CEventSignature14< _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13, _arg14 > { DEFINE_EVENTID_INTERNAL( _eventName ); } #define DEFINE_EVENT1_WITHNAMES( _eventName, _arg1, _arg1Name ) \ DEFINE_EVENT1( _eventName, _arg1 ) #define DEFINE_EVENT2_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name ) \ DEFINE_EVENT2( _eventName, _arg1, _arg2 ) #define DEFINE_EVENT3_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name ) \ DEFINE_EVENT3( _eventName, _arg1, _arg2, _arg3 ) #define DEFINE_EVENT4_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name ) \ DEFINE_EVENT4( _eventName, _arg1, _arg2, _arg3, _arg4 ) #define DEFINE_EVENT5_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name ) \ DEFINE_EVENT5( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5 ) #define DEFINE_EVENT6_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name ) \ DEFINE_EVENT6( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6 ) #define DEFINE_EVENT7_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name ) \ DEFINE_EVENT7( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7 ) #define DEFINE_EVENT8_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name ) \ DEFINE_EVENT8( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8 ) #define DEFINE_EVENT9_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name ) \ DEFINE_EVENT9( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9 ) #define DEFINE_EVENT10_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name ) \ DEFINE_EVENT10( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10 ) #define DEFINE_EVENT11_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name ) \ DEFINE_EVENT11( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11 ) #define DEFINE_EVENT12_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name, _arg12, _arg12Name ) \ DEFINE_EVENT12( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12 ) #define DEFINE_EVENT13_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name, _arg12, _arg12Name, _arg13, _arg13Name ) \ DEFINE_EVENT13( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13 ) #define DEFINE_EVENT14_WITHNAMES( _eventName, _arg1, _arg1Name, _arg2, _arg2Name, _arg3, _arg3Name, _arg4, _arg4Name, _arg5, _arg5Name, _arg6, _arg6Name, _arg7, _arg7Name, _arg8, _arg8Name, _arg9, _arg9Name, _arg10, _arg10Name, _arg11, _arg11Name, _arg12, _arg12Name, _arg13, _arg13Name, _arg14, _arg14Name ) \ DEFINE_EVENT14( _eventName, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12, _arg13, _arg14 ) #endif // IEVENTSYSTEM_H