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