1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Event sources.
12  *
13  *      By Peter Wang.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 /* Title: Event sources
19  */
20 
21 
22 #include "allegro5/allegro.h"
23 #include "allegro5/internal/aintern.h"
24 #include "allegro5/internal/aintern_dtor.h"
25 #include "allegro5/internal/aintern_events.h"
26 #include "allegro5/internal/aintern_system.h"
27 
28 
29 ALLEGRO_STATIC_ASSERT(evtsrc,
30    sizeof(ALLEGRO_EVENT_SOURCE_REAL) <= sizeof(ALLEGRO_EVENT_SOURCE));
31 
32 
33 
34 /* Internal function: _al_event_source_init
35  *  Initialise an event source structure.
36  */
_al_event_source_init(ALLEGRO_EVENT_SOURCE * es)37 void _al_event_source_init(ALLEGRO_EVENT_SOURCE *es)
38 {
39    ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
40 
41    memset(es, 0, sizeof(*es));
42    _AL_MARK_MUTEX_UNINITED(this->mutex);
43    _al_mutex_init(&this->mutex);
44    _al_vector_init(&this->queues, sizeof(ALLEGRO_EVENT_QUEUE *));
45    this->data = 0;
46 }
47 
48 
49 
50 /* Internal function: _al_event_source_free
51  *  Free the resources using by an event source structure.  It
52  *  automatically unregisters the event source from all the event
53  *  queues it is currently registered with.
54  */
_al_event_source_free(ALLEGRO_EVENT_SOURCE * es)55 void _al_event_source_free(ALLEGRO_EVENT_SOURCE *es)
56 {
57    ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
58 
59    /* Unregister from all queues. */
60    while (!_al_vector_is_empty(&this->queues)) {
61       ALLEGRO_EVENT_QUEUE **slot = _al_vector_ref_back(&this->queues);
62       al_unregister_event_source(*slot, es);
63    }
64 
65    _al_vector_free(&this->queues);
66 
67    _al_mutex_destroy(&this->mutex);
68 }
69 
70 
71 
72 /* Internal function: _al_event_source_lock
73  *  Lock the event source.  See below for when you should call this function.
74  */
_al_event_source_lock(ALLEGRO_EVENT_SOURCE * es)75 void _al_event_source_lock(ALLEGRO_EVENT_SOURCE *es)
76 {
77    ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
78 
79    _al_mutex_lock(&this->mutex);
80 }
81 
82 
83 
84 /* Internal function: _al_event_source_unlock
85  *  Unlock the event source.
86  */
_al_event_source_unlock(ALLEGRO_EVENT_SOURCE * es)87 void _al_event_source_unlock(ALLEGRO_EVENT_SOURCE *es)
88 {
89    ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
90 
91    _al_mutex_unlock(&this->mutex);
92 }
93 
94 
95 
96 /* Internal function: _al_event_source_on_registration_to_queue
97  *  This function is called by al_register_event_source() when an
98  *  event source is registered to an event queue.  This gives the
99  *  event source a chance to remember which queues it is registered
100  *  to.
101  */
_al_event_source_on_registration_to_queue(ALLEGRO_EVENT_SOURCE * es,ALLEGRO_EVENT_QUEUE * queue)102 void _al_event_source_on_registration_to_queue(ALLEGRO_EVENT_SOURCE *es,
103    ALLEGRO_EVENT_QUEUE *queue)
104 {
105    _al_event_source_lock(es);
106    {
107       ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
108 
109       /* Add the queue to the source's list.  */
110       ALLEGRO_EVENT_QUEUE **slot = _al_vector_alloc_back(&this->queues);
111       *slot = queue;
112    }
113    _al_event_source_unlock(es);
114 }
115 
116 
117 
118 /* Internal function: _al_event_source_on_unregistration_from_queue
119  *  This function is called by al_unregister_event_source() when an
120  *  event source is unregistered from a queue.
121  */
_al_event_source_on_unregistration_from_queue(ALLEGRO_EVENT_SOURCE * es,ALLEGRO_EVENT_QUEUE * queue)122 void _al_event_source_on_unregistration_from_queue(ALLEGRO_EVENT_SOURCE *es,
123    ALLEGRO_EVENT_QUEUE *queue)
124 {
125    _al_event_source_lock(es);
126    {
127       ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
128 
129       _al_vector_find_and_delete(&this->queues, &queue);
130    }
131    _al_event_source_unlock(es);
132 }
133 
134 
135 
136 /* Internal function: _al_event_source_needs_to_generate_event
137  *  This function is called by modules that implement event sources
138  *  when some interesting thing happens.  They call this to check if
139  *  they should bother generating an event of the given type, i.e. if
140  *  the given event source is actually registered with one or more
141  *  event queues.  This is an optimisation to avoid allocating and
142  *  filling in unwanted event structures.
143  *
144  *  The event source must be _locked_ before calling this function.
145  *
146  *  [runs in background threads]
147  */
_al_event_source_needs_to_generate_event(ALLEGRO_EVENT_SOURCE * es)148 bool _al_event_source_needs_to_generate_event(ALLEGRO_EVENT_SOURCE *es)
149 {
150    ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
151 
152    /* We don't consider pausing of event queues, but it does not seem worth
153     * optimising for.
154     */
155    return !_al_vector_is_empty(&this->queues);
156 }
157 
158 
159 
160 /* Internal function: _al_event_source_emit_event
161  *  After an event structure has been filled in, it is time for the
162  *  event source to tell the event queues it knows of about the new
163  *  event.  Afterwards, the caller of this function should not touch
164  *  the event any more.
165  *
166  *  The event source must be _locked_ before calling this function.
167  *
168  *  [runs in background threads]
169  */
_al_event_source_emit_event(ALLEGRO_EVENT_SOURCE * es,ALLEGRO_EVENT * event)170 void _al_event_source_emit_event(ALLEGRO_EVENT_SOURCE *es, ALLEGRO_EVENT *event)
171 {
172    ALLEGRO_EVENT_SOURCE_REAL *this = (ALLEGRO_EVENT_SOURCE_REAL *)es;
173 
174    event->any.source = es;
175 
176    /* Push the event to all the queues that this event source is
177     * registered to.
178     */
179    {
180       size_t num_queues = _al_vector_size(&this->queues);
181       unsigned int i;
182       ALLEGRO_EVENT_QUEUE **slot;
183 
184       for (i = 0; i < num_queues; i++) {
185          slot = _al_vector_ref(&this->queues, i);
186          _al_event_queue_push_event(*slot, event);
187       }
188    }
189 }
190 
191 
192 
193 /* Function: al_init_user_event_source
194  */
al_init_user_event_source(ALLEGRO_EVENT_SOURCE * src)195 void al_init_user_event_source(ALLEGRO_EVENT_SOURCE *src)
196 {
197    ASSERT(src);
198 
199    _al_event_source_init(src);
200 }
201 
202 
203 
204 /* Function: al_destroy_user_event_source
205  */
al_destroy_user_event_source(ALLEGRO_EVENT_SOURCE * src)206 void al_destroy_user_event_source(ALLEGRO_EVENT_SOURCE *src)
207 {
208    if (src) {
209       _al_event_source_free(src);
210    }
211 }
212 
213 
214 
215 /* Function: al_emit_user_event
216  */
al_emit_user_event(ALLEGRO_EVENT_SOURCE * src,ALLEGRO_EVENT * event,void (* dtor)(ALLEGRO_USER_EVENT *))217 bool al_emit_user_event(ALLEGRO_EVENT_SOURCE *src,
218    ALLEGRO_EVENT *event, void (*dtor)(ALLEGRO_USER_EVENT *))
219 {
220    size_t num_queues;
221    bool rc;
222 
223    ASSERT(src);
224    ASSERT(event);
225 
226    if (dtor) {
227       ALLEGRO_USER_EVENT_DESCRIPTOR *descr = al_malloc(sizeof(*descr));
228       descr->refcount = 0;
229       descr->dtor = dtor;
230       event->user.__internal__descr = descr;
231    }
232    else {
233       event->user.__internal__descr = NULL;
234    }
235 
236    _al_event_source_lock(src);
237    {
238       ALLEGRO_EVENT_SOURCE_REAL *rsrc = (ALLEGRO_EVENT_SOURCE_REAL *)src;
239 
240       num_queues = _al_vector_size(&rsrc->queues);
241       if (num_queues > 0) {
242          event->any.timestamp = al_get_time();
243          _al_event_source_emit_event(src, event);
244          rc = true;
245       }
246       else {
247          rc = false;
248       }
249    }
250    _al_event_source_unlock(src);
251 
252    if (dtor && !rc) {
253       dtor(&event->user);
254       al_free(event->user.__internal__descr);
255    }
256 
257    return rc;
258 }
259 
260 
261 
262 /* Function: al_set_event_source_data
263  */
al_set_event_source_data(ALLEGRO_EVENT_SOURCE * source,intptr_t data)264 void al_set_event_source_data(ALLEGRO_EVENT_SOURCE *source, intptr_t data)
265 {
266    ALLEGRO_EVENT_SOURCE_REAL *const rsource = (ALLEGRO_EVENT_SOURCE_REAL *)source;
267    rsource->data = data;
268 }
269 
270 
271 
272 /* Function: al_get_event_source_data
273  */
al_get_event_source_data(const ALLEGRO_EVENT_SOURCE * source)274 intptr_t al_get_event_source_data(const ALLEGRO_EVENT_SOURCE *source)
275 {
276    const ALLEGRO_EVENT_SOURCE_REAL *const rsource = (ALLEGRO_EVENT_SOURCE_REAL *)source;
277    return rsource->data;
278 }
279 
280 
281 
282 /*
283  * Local Variables:
284  * c-basic-offset: 3
285  * indent-tabs-mode: nil
286  * End:
287  */
288 /* vim: set sts=3 sw=3 et: */
289