neoGFX
Cross-platform C++ app/game engine
event.hpp
Go to the documentation of this file.
1 // event.hpp
2 /*
3 Transplanted from neogfx C++ GUI Library
4 Copyright (c) 2015-2018 Leigh Johnston. All Rights Reserved.
5 
6 This program is free software: you can redistribute it and / or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #pragma once
21 
22 #include <neolib/neolib.hpp>
23 #include <vector>
24 #include <deque>
25 #include <optional>
26 #include <mutex>
27 #include <atomic>
28 
29 #include <neolib/scoped.hpp>
30 #include <neolib/lifetime.hpp>
31 #include <neolib/jar.hpp>
32 #include <neolib/i_event.hpp>
33 
34 namespace neolib
35 {
36  class sink;
37 
39  {
40  public:
41  struct no_control : std::logic_error { no_control() : std::logic_error{ "neolib::event_handle::no_control" } {} };
42  public:
43  event_handle(i_event_control& aControl, cookie aId) :
44  iControl{ &aControl }, iRef{ aControl.get(), aId }, iPrimary{ true }
45  {
46  if (have_control())
47  control().add_ref();
48  }
49  event_handle(const event_handle& aOther) :
50  iControl{ aOther.iControl }, iRef{ aOther.iRef }, iPrimary{ false }
51  {
52  if (have_control())
53  control().add_ref();
54  }
56  iControl{ aOther.iControl }, iRef{ aOther.iRef }, iPrimary{ false }
57  {
58  aOther.iPrimary = false;
59  if (have_control())
60  control().add_ref();
61  }
63  {
64  if (have_control())
65  {
66  if (!control().valid() || primary())
67  iRef.reset();
68  control().release();
69  }
70  }
71  public:
73  {
74  if (&aRhs == this)
75  return *this;
76  auto oldControl = iControl;
77  iControl = aRhs.iControl;
78  if (have_control())
79  control().add_ref();
80  if (oldControl != nullptr)
81  oldControl->release();
82  iRef = aRhs.iRef;
83  return *this;
84  }
85  public:
86  bool have_control() const
87  {
88  return iControl != nullptr;
89  }
91  {
92  if (have_control())
93  return *iControl;
94  throw no_control();
95  }
96  cookie id() const
97  {
98  return iRef.cookie();
99  }
100  bool primary() const
101  {
102  return iPrimary;
103  }
105  {
106  if (control().valid())
108  return *this;
109  }
110  private:
111  i_event_control* iControl;
112  cookie_ref_ptr iRef;
113  bool iPrimary;
114  };
115 
117  {
118  public:
119  struct no_event : std::logic_error { no_event() : std::logic_error{ "neolib::event_control::no_event" } {} };
120  public:
122  iEvent{ &aEvent }, iRefCount{ 0u }
123  {
124  }
126  {
127  if (valid())
128  get().release_control();
129  }
130  public:
131  void add_ref() override
132  {
133  ++iRefCount;
134  }
135  void release() override
136  {
137  if (--iRefCount == 0u)
138  delete this;
139  }
140  bool valid() const override
141  {
142  return iEvent != nullptr;
143  }
144  i_event& get() const override
145  {
146  if (valid())
147  return *iEvent;
148  throw no_event();
149  }
150  public:
151  void reset() override
152  {
153  iEvent = nullptr;
154  }
155  private:
156  std::atomic<i_event*> iEvent;
157  std::atomic<uint32_t> iRefCount;
158  };
159 
160  template <typename... Args>
162  {
163  template <typename...>
164  friend class event;
165  friend class async_event_queue;
166  private:
167  typedef std::function<void(Args...)> function_type;
168  typedef std::shared_ptr<function_type> handler_ptr;
169  typedef std::tuple<Args...> argument_pack;
170  public:
171  event_callback(const i_event& aEvent, handler_ptr aHandler, Args... aArguments) :
172  iEvent{ aEvent }, iHandler{ aHandler }, iArguments{ aArguments... }
173  {
174  }
175  public:
176  const i_event& event() const override
177  {
178  return iEvent;
179  }
180  void call() const override
181  {
182  std::apply(*iHandler, iArguments);
183  }
184  private:
185  const i_event& iEvent;
186  handler_ptr iHandler;
187  argument_pack iArguments;
188  };
189 
190  class async_task;
191  class callback_timer;
192 
194  {
195  template <typename...>
196  friend class event;
197  public:
198  struct async_event_queue_needs_a_task : std::logic_error { async_event_queue_needs_a_task() : std::logic_error("neogfx::async_event_queue::async_event_queue_needs_a_task") {} };
199  struct async_event_queue_already_instantiated : std::logic_error { async_event_queue_already_instantiated() : std::logic_error("neogfx::async_event_queue::async_event_queue_already_instantiated") {} };
200  struct async_event_queue_terminated : std::logic_error { async_event_queue_terminated() : std::logic_error("neogfx::async_event_queue::async_event_queue_terminated") {} };
201  struct event_not_found : std::logic_error { event_not_found() : std::logic_error("neogfx::async_event_queue::event_not_found") {} };
202  private:
203  typedef uint64_t transaction;
204  typedef std::optional<transaction> optional_transaction;
205  typedef std::unique_ptr<i_event_callback> callback_ptr;
206  typedef std::deque<std::pair<transaction, callback_ptr>> event_list_t;
207  public:
208  static async_event_queue& instance();
209  static async_event_queue& instance(async_task& aTask);
211  private:
213  static async_event_queue& get_instance(async_task* aTask);
214  public:
215  bool exec();
216  transaction enqueue(callback_ptr aCallback, const optional_transaction& aTransaction = {})
217  {
218  return add(std::move(aCallback), aTransaction);
219  }
220  void unqueue(const i_event& aEvent);
221  void terminate();
222  public:
223  i_event_filter_registry& filter_registry();
224  private:
225  bool terminated() const;
226  transaction add(callback_ptr aCallback, const optional_transaction& aTransaction);
227  void remove(const i_event& aEvent);
228  bool has(const i_event& aEvent) const;
229  bool publish_events();
230  private:
231  async_task* iTask;
232  std::recursive_mutex iMutex;
233  std::unique_ptr<callback_timer> iTimer;
234  event_list_t iEvents;
235  std::atomic<bool> iTerminated;
236  destroyed_flag iTaskDestroyed;
237  std::atomic<uint32_t> iPublishNestingLevel;
238  std::vector<std::unique_ptr<event_list_t>> iPublishCache;
239  transaction iNextTransaction;
240  };
241 
243  {
244  Default,
245  Synchronous,
247  Asynchronous,
249  };
250 
251  template <typename... Args>
252  class event : public i_event, public lifetime
253  {
254  typedef event<Args...> self_type;
255  friend class sink;
256  friend class async_event_queue;
257  private:
258  typedef std::optional<std::scoped_lock<std::recursive_mutex>> optional_scoped_lock;
259  typedef typename event_callback<Args...>::function_type function_type;
260  typedef typename event_callback<Args...>::handler_ptr handler_ptr;
261  typedef async_event_queue::optional_transaction optional_async_transaction;
262  struct queue_ref
263  {
265  destroyed_flag queueDestroyed;
266 
267  queue_ref(async_event_queue& queue) :
268  queue{ queue },
269  queueDestroyed{ queue }
270  {}
271  };
272  typedef std::shared_ptr<queue_ref> queue_ref_ptr;
273  struct handler
274  {
275  queue_ref_ptr queueRef;
276  uint32_t referenceCount;
277  const void* clientId;
278  handler_ptr callback;
279  bool handleInSameThreadAsEmitter;
280  uint64_t triggerId = 0ull;
281 
282  handler(
284  const void* clientId,
285  handler_ptr callback,
286  bool handleInSameThreadAsEmitter = false) :
287  queueRef{ std::make_shared<queue_ref>(queue) },
288  referenceCount{ 0u },
289  clientId{ clientId },
290  callback{ callback },
291  handleInSameThreadAsEmitter{ handleInSameThreadAsEmitter }
292  {}
293  };
295  struct context
296  {
297  bool accepted;
298  std::atomic<bool> handlersChanged;
299  context() :
300  accepted{ false },
301  handlersChanged{ false }
302  {
303  }
304  context(const context& aOther) :
305  accepted{ aOther.accepted },
306  handlersChanged{ aOther.handlersChanged.load() }
307  {
308  }
309  context& operator=(const context& aOther)
310  {
311  accepted = aOther.accepted;
312  handlersChanged = aOther.handlersChanged.load();
313  return *this;
314  }
315  };
316  typedef std::vector<context> context_list_t;
317  struct instance_data
318  {
319  bool ignoreErrors = false;
321  handler_list_t handlers;
322  context_list_t contexts;
323  bool triggering = false;
324  uint64_t triggerId = 0ull;
325  std::atomic<bool> handlersChanged = false;
326  std::atomic<uint32_t> filterCount;
327  };
328  public:
329  event() : iAlias{ *this }, iMutex{ std::make_shared<std::recursive_mutex>() }, iControl{ nullptr }, iInstanceDataPtr{ nullptr }
330  {
331  }
332  event(const event&) = delete;
333  virtual ~event()
334  {
335  if (filtered())
337  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
338  if (is_controlled())
339  {
340  control().reset();
341  control().release();
342  }
343  set_destroying();
344  clear();
345  }
346  public:
347  self_type& operator=(const self_type&) = delete;
348  public:
349  std::recursive_mutex& mutex() const
350  {
351  return *iMutex;
352  }
353  public:
354  void release_control() override
355  {
356  if (iControl != nullptr)
357  {
358  iControl.load()->reset();
359  iControl.store(nullptr);
360  }
361  }
362  void handle_in_same_thread_as_emitter(cookie aHandleId) override
363  {
364  instance().handlers[aHandleId].handleInSameThreadAsEmitter = true;
365  }
366  public:
367  void push_context() const override
368  {
369  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
370  instance().contexts.emplace_back();
371  }
372  void pop_context() const override
373  {
374  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
375  instance().contexts.pop_back();
376  }
377  public:
378  void pre_trigger() const override
379  {
380  if (filtered())
382  }
383  public:
385  {
386  instance().ignoreErrors = true;
387  }
389  {
390  return instance().triggerType;
391  }
393  {
394  instance().triggerType = aTriggerType;
395  }
396  bool trigger(Args... aArguments) const
397  {
398  if (!has_instance()) // no instance date means no subscribers so no point triggering.
399  return true;
400  switch (trigger_type())
401  {
405  default:
406  return sync_trigger(aArguments...);
409  async_trigger(aArguments...);
410  return true;
411  }
412  }
413  bool sync_trigger(Args... aArguments) const
414  {
415  if (!has_instance()) // no instance means no subscribers so no point triggering.
416  return true;
417  if (trigger_type() == event_trigger_type::SynchronousDontQueue)
418  unqueue();
419  auto mutex = iMutex;
420  optional_scoped_lock lock{ *mutex };
421  if (instance().handlers.empty() && !filtered())
422  return true;
423  destroyed_flag destroyed{ *this };
424  push_context();
425  if (filtered())
426  {
428  if (destroyed)
429  return true;
430  if (instance().contexts.back().accepted)
431  {
432  pop_context();
433  return false;
434  }
435  }
436  if (instance().handlers.empty())
437  return true;
438  scoped_flag sf{ instance().triggering };
439  if (!instance().triggering)
440  {
441  instance().triggering = true;
442  instance().triggerId = 0ull;
443  for (auto& handler : instance().handlers)
444  handler.triggerId = 0ull;
445  }
446  auto triggerId = ++instance().triggerId;
447  optional_async_transaction transaction;
448  for (std::size_t handlerIndex = {}; handlerIndex < instance().handlers.size();)
449  {
450  auto& handler = instance().handlers.at_index(handlerIndex++);
451  if (handler.triggerId < triggerId)
452  handler.triggerId = triggerId;
453  else if (handler.triggerId == triggerId)
454  continue;
455  try
456  {
457  transaction = enqueue(lock, handler, false, transaction, aArguments...);
458  if (destroyed)
459  return true;
460  }
461  catch (...)
462  {
463  pop_context();
464  throw;
465  }
466  if (destroyed)
467  return true;
468  if (instance().contexts.back().accepted)
469  {
470  pop_context();
471  return false;
472  }
473  if (instance().handlersChanged.exchange(false))
474  handlerIndex = {};
475  }
476  pop_context();
477  return true;
478  }
479  void async_trigger(Args... aArguments) const
480  {
481  if (!has_instance()) // no instance means no subscribers so no point triggering.
482  return;
483  if (trigger_type() == event_trigger_type::AsynchronousDontQueue)
484  unqueue();
485  auto mutex = iMutex;
486  optional_scoped_lock lock{ *mutex };
487  if (instance().handlers.empty())
488  return;
489  destroyed_flag destroyed{ *this };
490  scoped_flag sf{ instance().triggering };
491  if (!instance().triggering)
492  {
493  instance().triggering = true;
494  instance().triggerId = 0ull;
495  for (auto& handler : instance().handlers)
496  handler.triggerId = 0ull;
497  }
498  auto triggerId = ++instance().triggerId;
499  optional_async_transaction transaction;
500  for (std::size_t handlerIndex = {}; handlerIndex < instance().handlers.size();)
501  {
502  auto& handler = instance().handlers.at_index(handlerIndex++);
503  if (handler.triggerId < triggerId)
504  handler.triggerId = triggerId;
505  else if (handler.triggerId == triggerId)
506  continue;
507  transaction = enqueue(lock, handler, true, transaction, aArguments...);
508  if (destroyed)
509  return;
510  if (instance().handlersChanged.exchange(false))
511  handlerIndex = {};
512  }
513  }
514  bool accepted() const override
515  {
516  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
517  return !instance().contexts.empty() ? instance().contexts.back().accepted : false;
518  }
519  void accept() const override
520  {
521  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
522  instance().contexts.back().accepted = true;
523  }
524  void ignore() const override
525  {
526  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
527  instance().contexts.back().accepted = false;
528  }
529  public:
530  bool filtered() const override
531  {
532  return instance().filterCount > 0u;
533  }
534  void filter_added() const override
535  {
536  ++instance().filterCount;
537  }
538  void filter_removed() const override
539  {
540  --instance().filterCount;
541  }
542  void filters_removed() const override
543  {
544  instance().filterCount = 0u;
545  }
546  public:
547  event_handle subscribe(const function_type& aHandlerCallback, const void* aUniqueId = nullptr) const
548  {
549  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
550  invalidate_handler_list();
551  return event_handle{ control(), instance().handlers.emplace(async_event_queue::instance(), aUniqueId, std::make_shared<function_type>(aHandlerCallback)) };
552  }
553  event_handle operator()(const function_type& aHandlerCallback, const void* aUniqueId = nullptr) const
554  {
555  return subscribe(aHandlerCallback, aUniqueId);
556  }
557  template <typename T>
558  event_handle subscribe(const function_type& aHandlerCallback, const T* aClientId) const
559  {
560  return subscribe(aHandlerCallback, static_cast<const void*>(aClientId));
561  }
562  template <typename T>
563  event_handle operator()(const function_type& aHandlerCallback, const T* aClientId) const
564  {
565  return subscribe(aHandlerCallback, static_cast<const void*>(aClientId));
566  }
567  template <typename T>
568  event_handle subscribe(const function_type& aHandlerCallback, const T& aClientId) const
569  {
570  return subscribe(aHandlerCallback, static_cast<const void*>(&aClientId));
571  }
572  template <typename T>
573  event_handle operator()(const function_type& aHandlerCallback, const T& aClientId) const
574  {
575  return subscribe(aHandlerCallback, static_cast<const void*>(&aClientId));
576  }
577  void unsubscribe(event_handle aHandle) const
578  {
579  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
580  invalidate_handler_list();
581  instance().handlers.remove(aHandle.id());
582  }
583  void unsubscribe(const void* aClientId) const
584  {
585  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
586  invalidate_handler_list();
587  for (auto h = instance().handlers.begin(); h != instance().handlers.end();)
588  if (h->clientId == aClientId)
589  h = instance().handlers.erase(h);
590  else
591  ++h;
592  }
593  template <typename T>
594  void unsubscribe(const T* aClientId) const
595  {
596  return unsubscribe(static_cast<const void*>(aClientId));
597  }
598  template <typename T>
599  void unsubscribe(const T& aClientId) const
600  {
601  return unsubscribe(static_cast<const void*>(&aClientId));
602  }
603  private:
604  void add_ref(cookie aCookie) override
605  {
606  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
607  ++instance().handlers[aCookie].referenceCount;
608  }
609  void release(cookie aCookie) override
610  {
611  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
612  if (--instance().handlers[aCookie].referenceCount == 0u)
613  instance().handlers.remove(aCookie);
614  }
615  long use_count(cookie aCookie) const override
616  {
617  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
618  return instance().handlers[aCookie].referenceCount;
619  }
620  private:
621  void invalidate_handler_list() const
622  {
623  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
624  instance().handlersChanged = true;
625  for (auto& context : instance().contexts)
626  context.handlersChanged = true;
627  }
628  optional_async_transaction enqueue(optional_scoped_lock& lock, handler& aHandler, bool aAsync, const optional_async_transaction& aAsyncTransaction, Args... aArguments) const
629  {
630  optional_async_transaction transaction;
631  auto& emitterQueue = async_event_queue::instance();
632  if (!aAsync && !aHandler.queueRef->queueDestroyed && &aHandler.queueRef->queue == &emitterQueue)
633  {
634  auto mutex = iMutex;
635  auto callback = aHandler.callback;
636  lock = std::nullopt;
637  (*callback)(aArguments...);
638  lock.emplace(*mutex);
639  }
640  else
641  {
642  auto ecb = std::make_unique<event_callback<Args...>>(*this, aHandler.callback, aArguments...);
643  if (aHandler.handleInSameThreadAsEmitter)
644  transaction = emitterQueue.enqueue(std::move(ecb), aAsyncTransaction);
645  else
646  {
647  if (!aHandler.queueRef->queueDestroyed)
648  transaction = aHandler.queueRef->queue.enqueue(std::move(ecb), aAsyncTransaction);
649  else if (!instance().ignoreErrors)
650  throw event_queue_destroyed();
651  }
652  }
653  return transaction;
654  }
655  void unqueue() const
656  {
657  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
658  std::unordered_set<async_event_queue*> queues;
659  for (auto const& h : instance().handlers)
660  if (!h.queueRef->queueDestroyed)
661  queues.insert(&h.queueRef->queue);
662  for (auto const& q : queues)
663  q->unqueue(*this);
664  }
665  void clear()
666  {
667  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
668  for (auto& h : instance().handlers)
669  if (!h.queueRef->queueDestroyed)
670  h.queueRef->queue.remove(*this);
671  iInstanceDataPtr = nullptr;
672  iInstanceData = std::nullopt;
673  }
674  bool is_controlled() const
675  {
676  return iControl != nullptr;
677  }
678  i_event_control& control() const
679  {
680  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
681  if (iControl == nullptr)
682  {
683  iControl = new event_control{ iAlias };
684  iControl.load()->add_ref();
685  }
686  return *iControl;
687  }
688  bool has_instance() const
689  {
690  return iInstanceDataPtr != nullptr;
691  }
692  instance_data& instance() const
693  {
694  if (iInstanceDataPtr != nullptr)
695  return *iInstanceDataPtr;
696  std::scoped_lock<std::recursive_mutex> lock{ *iMutex };
697  iInstanceData.emplace();
698  iInstanceDataPtr = &*iInstanceData;
699  return *iInstanceDataPtr;
700  }
701  private:
702  self_type& iAlias; // bit of a hack: most event operations are logically const as we want to be able to trigger events from const methods of the containing object
703  mutable std::shared_ptr<std::recursive_mutex> iMutex;
704  mutable std::atomic<i_event_control*> iControl;
705  mutable std::optional<instance_data> iInstanceData;
706  mutable std::atomic<instance_data*> iInstanceDataPtr;
707  };
708 
709  class sink
710  {
711  public:
713  {
714  }
715  sink(const event_handle& aHandle)
716  {
717  iHandles.push_back(aHandle);
718  }
719  sink(event_handle&& aHandle)
720  {
721  iHandles.push_back(std::move(aHandle));
722  }
723  sink(const sink& aSink) :
724  iHandles{ aSink.iHandles }
725  {
726  }
727  virtual ~sink()
728  {
729  clear();
730  }
731  public:
732  sink& operator=(const sink& aSink)
733  {
734  if (this == &aSink)
735  return *this;
736  iHandles = aSink.iHandles;
737  return *this;
738  }
739  public:
740  sink& operator=(const event_handle& aHandle)
741  {
742  return *this = sink{ aHandle };
743  }
745  {
746  return *this = sink{ std::move(aHandle) };
747  }
748  sink& operator+=(const event_handle& aHandle)
749  {
750  sink s{ aHandle };
751  iHandles.insert(iHandles.end(), s.iHandles.begin(), s.iHandles.end());
752  return *this;
753  }
755  {
756  sink s{ std::move(aHandle) };
757  iHandles.insert(iHandles.end(), s.iHandles.begin(), s.iHandles.end());
758  return *this;
759  }
760  public:
761  void clear()
762  {
763  iHandles.clear();
764  }
765  private:
766  mutable std::vector<event_handle> iHandles;
767  };
768 }
static async_event_queue & instance()
friend class async_event_queue
Definition: event.hpp:165
event_handle operator()(const function_type &aHandlerCallback, const void *aUniqueId=nullptr) const
Definition: event.hpp:553
void clear()
Definition: event.hpp:761
void release_control() override
Definition: event.hpp:354
std::recursive_mutex & mutex() const
Definition: event.hpp:349
bool valid() const override
Definition: event.hpp:140
void filter_added() const override
Definition: event.hpp:534
void ignore_errors()
Definition: event.hpp:384
sink & operator+=(event_handle &&aHandle)
Definition: event.hpp:754
void unsubscribe(event_handle aHandle) const
Definition: event.hpp:577
event_handle subscribe(const function_type &aHandlerCallback, const T *aClientId) const
Definition: event.hpp:558
void add_ref() override
Definition: event.hpp:131
const i_event & event() const override
Definition: event.hpp:176
event_callback(const i_event &aEvent, handler_ptr aHandler, Args... aArguments)
Definition: event.hpp:171
virtual ~sink()
Definition: event.hpp:727
void accept() const override
Definition: event.hpp:519
i_event_control & control() const
Definition: event.hpp:90
event_handle subscribe(const function_type &aHandlerCallback, const void *aUniqueId=nullptr) const
Definition: event.hpp:547
bool primary() const
Definition: event.hpp:100
void push_context() const override
Definition: event.hpp:367
event_handle subscribe(const function_type &aHandlerCallback, const T &aClientId) const
Definition: event.hpp:568
virtual void release()=0
sink(event_handle &&aHandle)
Definition: event.hpp:719
virtual i_event & get() const =0
transaction enqueue(callback_ptr aCallback, const optional_transaction &aTransaction={})
Definition: event.hpp:216
void filters_removed() const override
Definition: event.hpp:542
event_control(i_event &aEvent)
Definition: event.hpp:121
friend class event
Definition: event.hpp:196
virtual void handle_in_same_thread_as_emitter(cookie aHandleId)=0
void release() override
Definition: event.hpp:135
virtual void uninstall_event_filter(i_event_filter &aFilter, const i_event &aEvent)=0
event_handle(i_event_control &aControl, cookie aId)
Definition: event.hpp:43
bool accepted() const override
Definition: event.hpp:514
virtual void pre_filter_event(const i_event &aEvent) const =0
sink(const sink &aSink)
Definition: event.hpp:723
bool have_control() const
Definition: event.hpp:86
void async_trigger(Args... aArguments) const
Definition: event.hpp:479
sink & operator=(const sink &aSink)
Definition: event.hpp:732
void unsubscribe(const void *aClientId) const
Definition: event.hpp:583
std::vector< operation > queue
event_handle & operator=(const event_handle &aRhs)
Definition: event.hpp:72
i_event_filter_registry & filter_registry()
event_handle operator()(const function_type &aHandlerCallback, const T &aClientId) const
Definition: event.hpp:573
uint32_t cookie
Definition: jar.hpp:49
sink(const event_handle &aHandle)
Definition: event.hpp:715
friend class event
Definition: event.hpp:164
event_handle(const event_handle &aOther)
Definition: event.hpp:49
void call() const override
Definition: event.hpp:180
bool sync_trigger(Args... aArguments) const
Definition: event.hpp:413
virtual void add_ref()=0
void unsubscribe(const T &aClientId) const
Definition: event.hpp:599
event_trigger_type trigger_type() const
Definition: event.hpp:388
event_handle operator()(const function_type &aHandlerCallback, const T *aClientId) const
Definition: event.hpp:563
sink & operator=(event_handle &&aHandle)
Definition: event.hpp:744
virtual void reset()=0
cookie id() const
Definition: event.hpp:96
event_handle & operator~()
Definition: event.hpp:104
event_handle(event_handle &&aOther)
Definition: event.hpp:55
void set_trigger_type(event_trigger_type aTriggerType)
Definition: event.hpp:392
sink & operator+=(const event_handle &aHandle)
Definition: event.hpp:748
void reset() override
Definition: event.hpp:151
bool filtered() const override
Definition: event.hpp:530
virtual void filter_event(const i_event &aEvent) const =0
void ignore() const override
Definition: event.hpp:524
void pre_trigger() const override
Definition: event.hpp:378
auto destroyed(Object &aObject, const Handler aHandler)
Definition: i_object.hpp:64
event_trigger_type
Definition: event.hpp:242
sink & operator=(const event_handle &aHandle)
Definition: event.hpp:740
void pop_context() const override
Definition: event.hpp:372
bool trigger(Args... aArguments) const
Definition: event.hpp:396
void filter_removed() const override
Definition: event.hpp:538
virtual ~event()
Definition: event.hpp:333
void unsubscribe(const T *aClientId) const
Definition: event.hpp:594
void handle_in_same_thread_as_emitter(cookie aHandleId) override
Definition: event.hpp:362