Panda3D
eventHandler.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file eventHandler.cxx
10  * @author drose
11  * @date 1999-02-08
12  */
13 
14 #include "eventHandler.h"
15 #include "eventQueue.h"
16 #include "config_event.h"
17 
18 using std::string;
19 
20 TypeHandle EventHandler::_type_handle;
21 
22 EventHandler *EventHandler::_global_event_handler = nullptr;
23 
24 
25 /**
26  *
27  */
28 EventHandler::
29 EventHandler(EventQueue *ev_queue) : _queue(*ev_queue) {
30 }
31 
32 /**
33  * Returns a pending future that will be marked as done when the event is next
34  * fired.
35  */
37 get_future(const string &event_name) {
38  Futures::iterator fi;
39  fi = _futures.find(event_name);
40 
41  // If we already have a future, but someone cancelled it, we need to create
42  // a new future instead.
43  if (fi != _futures.end() && !fi->second->cancelled()) {
44  return fi->second;
45  } else {
46  AsyncFuture *fut = new AsyncFuture;
47  _futures[event_name] = fut;
48  return fut;
49  }
50 }
51 
52 /**
53  * The main processing loop of the EventHandler. This function must be called
54  * periodically to service events. Walks through each pending event and calls
55  * its assigned hooks.
56  */
57 void EventHandler::
59  while (!_queue.is_queue_empty()) {
60  dispatch_event(_queue.dequeue_event());
61  }
62 }
63 
64 /**
65  * Calls the hooks assigned to the indicated single event.
66  */
67 void EventHandler::
68 dispatch_event(const Event *event) {
69  nassertv(event != nullptr);
70 
71  // Is the event name defined in the hook table? It will be if anyone has
72  // ever assigned a hook to this particular event name.
73  Hooks::const_iterator hi;
74  hi = _hooks.find(event->get_name());
75 
76  if (hi != _hooks.end()) {
77  // Yes, it is! Now walk through all the functions assigned to that event
78  // name.
79  Functions copy_functions = (*hi).second;
80 
81  Functions::const_iterator fi;
82  for (fi = copy_functions.begin(); fi != copy_functions.end(); ++fi) {
83  if (event_cat.is_spam()) {
84  event_cat->spam()
85  << "calling callback 0x" << (void*)(*fi)
86  << " for event '" << event->get_name() << "'"
87  << std::endl;
88  }
89  (*fi)(event);
90  }
91  }
92 
93  // now for callback hooks
94  CallbackHooks::const_iterator chi;
95  chi = _cbhooks.find(event->get_name());
96 
97  if (chi != _cbhooks.end()) {
98  // found one
99  CallbackFunctions copy_functions = (*chi).second;
100 
101  CallbackFunctions::const_iterator cfi;
102  for (cfi = copy_functions.begin(); cfi != copy_functions.end(); ++cfi) {
103  ((*cfi).first)(event, (*cfi).second);
104  }
105  }
106 
107  // Finally, check for futures that need to be triggered.
108  Futures::iterator fi;
109  fi = _futures.find(event->get_name());
110 
111  if (fi != _futures.end()) {
112  AsyncFuture *fut = (*fi).second;
113  if (!fut->done()) {
114  fut->set_result((TypedReferenceCount *)event);
115  }
116  _futures.erase(fi);
117  }
118 }
119 
120 
121 /**
122  *
123  */
124 void EventHandler::
125 write(std::ostream &out) const {
126  Hooks::const_iterator hi;
127  hi = _hooks.begin();
128 
129  CallbackHooks::const_iterator chi;
130  chi = _cbhooks.begin();
131 
132  while (hi != _hooks.end() && chi != _cbhooks.end()) {
133  if ((*hi).first < (*chi).first) {
134  write_hook(out, *hi);
135  ++hi;
136  } else if ((*chi).first < (*hi).first) {
137  write_cbhook(out, *chi);
138  ++chi;
139  } else {
140  write_hook(out, *hi);
141  write_cbhook(out, *chi);
142  ++hi;
143  ++chi;
144  }
145  }
146 
147  while (hi != _hooks.end()) {
148  write_hook(out, *hi);
149  ++hi;
150  }
151 
152  while (chi != _cbhooks.end()) {
153  write_cbhook(out, *chi);
154  ++chi;
155  }
156 }
157 
158 
159 
160 /**
161  * Adds the indicated function to the list of those that will be called when
162  * the named event is thrown. Returns true if the function was successfully
163  * added, false if it was already defined on the indicated event name.
164  */
165 bool EventHandler::
166 add_hook(const string &event_name, EventFunction *function) {
167  if (event_cat.is_debug()) {
168  event_cat.debug()
169  << "adding hook for event '" << event_name
170  << "' with function 0x" << (void*)function << std::endl;
171  }
172  assert(!event_name.empty());
173  assert(function);
174  return _hooks[event_name].insert(function).second;
175 }
176 
177 
178 /**
179  * Adds the indicated function to the list of those that will be called when
180  * the named event is thrown. Returns true if the function was successfully
181  * added, false if it was already defined on the indicated event name. This
182  * version records an untyped pointer to user callback data.
183  */
184 bool EventHandler::
185 add_hook(const string &event_name, EventCallbackFunction *function,
186  void *data) {
187  assert(!event_name.empty());
188  assert(function);
189  return _cbhooks[event_name].insert(CallbackFunction(function, data)).second;
190 }
191 
192 /**
193  * Returns true if there is any hook added on the indicated event name, false
194  * otherwise.
195  */
196 bool EventHandler::
197 has_hook(const string &event_name) const {
198  assert(!event_name.empty());
199  Hooks::const_iterator hi;
200  hi = _hooks.find(event_name);
201  if (hi != _hooks.end()) {
202  if (!(*hi).second.empty()) {
203  return true;
204  }
205  }
206 
207  CallbackHooks::const_iterator chi;
208  chi = _cbhooks.find(event_name);
209  if (chi != _cbhooks.end()) {
210  if (!(*chi).second.empty()) {
211  return true;
212  }
213  }
214 
215  return false;
216 }
217 
218 
219 /**
220  * Returns true if there is the hook added on the indicated event name and
221  * function pointer, false otherwise.
222  */
223 bool EventHandler::
224 has_hook(const string &event_name, EventFunction *function) const {
225  assert(!event_name.empty());
226  Hooks::const_iterator hi;
227  hi = _hooks.find(event_name);
228  if (hi != _hooks.end()) {
229  const Functions& functions = (*hi).second;
230  if (functions.find(function) != functions.end()) {
231  return true;
232  }
233  }
234 
235  return false;
236 }
237 
238 
239 /**
240  * Returns true if there is the hook added on the indicated event name,
241  * function pointer and callback data, false otherwise.
242  */
243 bool EventHandler::
244 has_hook(const string &event_name, EventCallbackFunction *function, void *data) const {
245  assert(!event_name.empty());
246  CallbackHooks::const_iterator chi;
247  chi = _cbhooks.find(event_name);
248  if (chi != _cbhooks.end()) {
249  const CallbackFunctions& cbfunctions = (*chi).second;
250  if (cbfunctions.find(CallbackFunction(function, data)) != cbfunctions.end()) {
251  return true;
252  }
253  }
254 
255  return false;
256 }
257 
258 
259 /**
260  * Removes the indicated function from the named event hook. Returns true if
261  * the hook was removed, false if it wasn't there in the first place.
262  */
263 bool EventHandler::
264 remove_hook(const string &event_name, EventFunction *function) {
265  assert(!event_name.empty());
266  assert(function);
267  return _hooks[event_name].erase(function) != 0;
268 }
269 
270 
271 /**
272  * Removes the indicated function from the named event hook. Returns true if
273  * the hook was removed, false if it wasn't there in the first place. This
274  * version takes an untyped pointer to user callback data.
275  */
276 bool EventHandler::
277 remove_hook(const string &event_name, EventCallbackFunction *function,
278  void *data) {
279  assert(!event_name.empty());
280  assert(function);
281  return _cbhooks[event_name].erase(CallbackFunction(function, data)) != 0;
282 }
283 
284 /**
285  * Removes all functions from the named event hook. Returns true if any
286  * functions were removed, false if there were no functions added to the hook.
287  */
288 bool EventHandler::
289 remove_hooks(const string &event_name) {
290  assert(!event_name.empty());
291  bool any_removed = false;
292 
293  Hooks::iterator hi = _hooks.find(event_name);
294  if (hi != _hooks.end()) {
295  if (!(*hi).second.empty()) {
296  any_removed = true;
297  }
298  _hooks.erase(hi);
299  }
300 
301  CallbackHooks::iterator chi = _cbhooks.find(event_name);
302  if (chi != _cbhooks.end()) {
303  if (!(*chi).second.empty()) {
304  any_removed = true;
305  }
306  _cbhooks.erase(chi);
307  }
308 
309  return any_removed;
310 }
311 
312 /**
313  * Removes all CallbackFunction hooks that have the indicated pointer as the
314  * associated data pointer.
315  */
316 bool EventHandler::
317 remove_hooks_with(void *data) {
318  bool any_removed = false;
319 
320  CallbackHooks::iterator chi;
321  for (chi = _cbhooks.begin(); chi != _cbhooks.end(); ++chi) {
322  CallbackFunctions &funcs = (*chi).second;
323  CallbackFunctions::iterator cfi;
324 
325  CallbackFunctions new_funcs;
326  for (cfi = funcs.begin(); cfi != funcs.end(); ++cfi) {
327  if ((*cfi).second == data) {
328  any_removed = true;
329  } else {
330  new_funcs.insert(*cfi);
331  }
332  }
333  funcs.swap(new_funcs);
334  }
335 
336  return any_removed;
337 }
338 
339 
340 /**
341  * Removes all hooks assigned to all events.
342  */
343 void EventHandler::
345  _hooks.clear();
346  _cbhooks.clear();
347 }
348 
349 /**
350  *
351  */
352 void EventHandler::
353 make_global_event_handler() {
355  _global_event_handler = new EventHandler(EventQueue::get_global_event_queue());
356 }
357 
358 
359 /**
360  *
361  */
362 void EventHandler::
363 write_hook(std::ostream &out, const EventHandler::Hooks::value_type &hook) const {
364  if (!hook.second.empty()) {
365  out << hook.first << " has " << hook.second.size() << " functions.\n";
366  }
367 }
368 
369 /**
370  *
371  */
372 void EventHandler::
373 write_cbhook(std::ostream &out, const EventHandler::CallbackHooks::value_type &hook) const {
374  if (!hook.second.empty()) {
375  out << hook.first << " has " << hook.second.size() << " callback functions.\n";
376  }
377 }
void remove_all_hooks()
Removes all hooks assigned to all events.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition: asyncFuture.h:61
bool remove_hook(const std::string &event_name, EventFunction *function)
Removes the indicated function from the named event hook.
A class to monitor events from the C++ side of things.
Definition: eventHandler.h:37
void init_memory_hook()
Any code that might need to use PANDA_MALLOC or PANDA_FREE, or any methods of the global memory_hook ...
Definition: dtoolbase.cxx:38
A base class for things which need to inherit from both TypedObject and from ReferenceCount.
static EventQueue * get_global_event_queue()
Returns a pointer to the one global EventQueue object.
Definition: eventQueue.I:19
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A queue of pending events.
Definition: eventQueue.h:29
virtual void dispatch_event(const Event *event)
Calls the hooks assigned to the indicated single event.
bool add_hook(const std::string &event_name, EventFunction *function)
Adds the indicated function to the list of those that will be called when the named event is thrown.
bool remove_hooks_with(void *data)
Removes all CallbackFunction hooks that have the indicated pointer as the associated data pointer.
bool done() const
Returns true if the future is done or has been cancelled.
Definition: asyncFuture.I:29
bool has_hook(const std::string &event_name) const
Returns true if there is any hook added on the indicated event name, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_result(std::nullptr_t)
Sets this future's result.
Definition: asyncFuture.I:92
bool remove_hooks(const std::string &event_name)
Removes all functions from the named event hook.
A named event, possibly with parameters.
Definition: event.h:33
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
AsyncFuture * get_future(const std::string &event_name)
Returns a pending future that will be marked as done when the event is next fired.
void process_events()
The main processing loop of the EventHandler.