1 /* 2 * hook.h 3 * Copyright 2011-2015 John Lindgren 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions, and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions, and the following disclaimer in the documentation 13 * provided with the distribution. 14 * 15 * This software is provided "as is" and without any warranty, express or 16 * implied. In no event shall the authors be liable for any damages arising from 17 * the use of this software. 18 */ 19 20 #ifndef LIBAUDCORE_HOOK_H 21 #define LIBAUDCORE_HOOK_H 22 23 #include <libaudcore/templates.h> 24 25 // Timer API. This API allows functions to be registered to run at a given 26 // periodic rate. The advantage of this API rather than QueuedFunc (see 27 // mainloop.h) is that multiple functions can run on the same timer tick, 28 // reducing CPU wakeups. 29 // ======================================================================== 30 31 enum class TimerRate 32 { 33 Hz1, 34 Hz4, 35 Hz10, 36 Hz30, 37 count 38 }; 39 40 typedef void (*TimerFunc)(void * data); 41 42 /* Adds <func> to the list of functions to be called at the given <rate>, 43 * unless it has already been added with the same <data>. */ 44 void timer_add(TimerRate rate, TimerFunc func, void * data = nullptr); 45 46 /* Removes all instances matching <func> and <data> from the list of functions 47 * to be called at the given <rate>. If <data> is nullptr, all instances 48 * matching <func> are removed. */ 49 void timer_remove(TimerRate rate, TimerFunc func, void * data = nullptr); 50 51 /* Convenience wrapper for C++ classes. Allows non-static member functions to 52 * be used as timer callbacks. The Timer should be made a member of the class 53 * in question so that timer_remove() is called automatically from the 54 * destructor. Note that the timer is not started automatically. */ 55 template<class T> 56 class Timer 57 { 58 public: Timer(TimerRate rate,T * target,void (T::* func)())59 Timer(TimerRate rate, T * target, void (T::*func)()) 60 : rate(rate), target(target), func(func) 61 { 62 } 63 start()64 void start() const { timer_add(rate, run, (void *)this); } stop()65 void stop() const { timer_remove(rate, run, (void *)this); } 66 ~Timer()67 ~Timer() { stop(); } 68 69 Timer(const Timer &) = delete; 70 void operator=(const Timer &) = delete; 71 72 private: 73 const TimerRate rate; 74 T * const target; 75 void (T::*const func)(); 76 run(void * timer_)77 static void run(void * timer_) 78 { 79 auto timer = (const Timer *)timer_; 80 (timer->target->*timer->func)(); 81 } 82 }; 83 84 // Hook API. This API allows functions to be registered to run when a given 85 // named event, or "hook", is called. 86 // ========================================================================= 87 88 typedef void (*HookFunction)(void * data, void * user); 89 90 /* Adds <func> to the list of functions to be called when the hook <name> is 91 * triggered. */ 92 void hook_associate(const char * name, HookFunction func, void * user); 93 94 /* Removes all instances matching <func> and <user> from the list of functions 95 * to be called when the hook <name> is triggered. If <user> is nullptr, all 96 * instances matching <func> are removed. */ 97 void hook_dissociate(const char * name, HookFunction func, 98 void * user = nullptr); 99 100 /* Triggers the hook <name>. */ 101 void hook_call(const char * name, void * data); 102 103 typedef void (*EventDestroyFunc)(void * data); 104 105 /* Schedules a call of the hook <name> from the program's main loop. 106 * If <destroy> is not nullptr, it will be called on <data> after the 107 * hook is called. */ 108 void event_queue(const char * name, void * data, 109 EventDestroyFunc destroy = nullptr); 110 111 /* Cancels pending hook calls matching <name> and <data>. If <data> is nullptr, 112 * all hook calls matching <name> are canceled. */ 113 void event_queue_cancel(const char * name, void * data = nullptr); 114 115 template<class T, class D> 116 struct HookTarget 117 { 118 using Func = void (T::*)(D); runHookTarget119 static void run(T * target, Func func, void * d) 120 { 121 (target->*func)(aud::from_ptr<D>(d)); 122 } 123 }; 124 125 template<class T> 126 struct HookTarget<T, void> 127 { 128 using Func = void (T::*)(); 129 static void run(T * target, Func func, void *) { (target->*func)(); } 130 }; 131 132 /* Convenience wrapper for C++ classes. Allows non-static member functions to 133 * be used as hook callbacks. The HookReceiver should be made a member of the 134 * class in question so that hook_dissociate() is called automatically from the 135 * destructor. */ 136 template<class T, class D = void> 137 class HookReceiver 138 { 139 public: 140 using Target = HookTarget<T, D>; 141 using Func = typename Target::Func; 142 143 constexpr HookReceiver(T * target, Func func) 144 : m_hook(nullptr), m_target(target), m_func(func) 145 { 146 } 147 148 HookReceiver(const char * hook, T * target, Func func) 149 : HookReceiver(target, func) 150 { 151 connect(hook); 152 } 153 154 ~HookReceiver() { disconnect(); } 155 156 HookReceiver(const HookReceiver &) = delete; 157 void operator=(const HookReceiver &) = delete; 158 159 void connect(const char * hook) 160 { 161 disconnect(); 162 hook_associate(hook, run, this); 163 m_hook = hook; 164 } 165 166 void disconnect() 167 { 168 if (!m_hook) 169 return; 170 hook_dissociate(m_hook, run, this); 171 m_hook = nullptr; 172 } 173 174 private: 175 const char * m_hook; 176 T * const m_target; 177 const Func m_func; 178 179 static void run(void * d, void * recv_) 180 { 181 auto recv = (const HookReceiver *)recv_; 182 Target::run(recv->m_target, recv->m_func, d); 183 } 184 }; 185 186 #endif /* LIBAUDCORE_HOOK_H */ 187