1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22
23 /* General event handling code for SDL */
24
25 #include "SDL.h"
26 #include "SDL_events.h"
27 #include "SDL_thread.h"
28 #include "SDL_events_c.h"
29 #include "../timer/SDL_timer_c.h"
30 #if !SDL_JOYSTICK_DISABLED
31 #include "../joystick/SDL_joystick_c.h"
32 #endif
33 #include "../video/SDL_sysvideo.h"
34 #include "SDL_syswm.h"
35
36 #undef SDL_PRIs64
37 #ifdef __WIN32__
38 #define SDL_PRIs64 "I64d"
39 #else
40 #define SDL_PRIs64 "lld"
41 #endif
42
43 /* An arbitrary limit so we don't have unbounded growth */
44 #define SDL_MAX_QUEUED_EVENTS 65535
45
46 typedef struct SDL_EventWatcher {
47 SDL_EventFilter callback;
48 void *userdata;
49 SDL_bool removed;
50 } SDL_EventWatcher;
51
52 static SDL_mutex *SDL_event_watchers_lock;
53 static SDL_EventWatcher SDL_EventOK;
54 static SDL_EventWatcher *SDL_event_watchers = NULL;
55 static int SDL_event_watchers_count = 0;
56 static SDL_bool SDL_event_watchers_dispatching = SDL_FALSE;
57 static SDL_bool SDL_event_watchers_removed = SDL_FALSE;
58
59 typedef struct {
60 Uint32 bits[8];
61 } SDL_DisabledEventBlock;
62
63 static SDL_DisabledEventBlock *SDL_disabled_events[256];
64 static Uint32 SDL_userevents = SDL_USEREVENT;
65
66 /* Private data -- event queue */
67 typedef struct _SDL_EventEntry
68 {
69 SDL_Event event;
70 SDL_SysWMmsg msg;
71 struct _SDL_EventEntry *prev;
72 struct _SDL_EventEntry *next;
73 } SDL_EventEntry;
74
75 typedef struct _SDL_SysWMEntry
76 {
77 SDL_SysWMmsg msg;
78 struct _SDL_SysWMEntry *next;
79 } SDL_SysWMEntry;
80
81 static struct
82 {
83 SDL_mutex *lock;
84 SDL_atomic_t active;
85 SDL_atomic_t count;
86 int max_events_seen;
87 SDL_EventEntry *head;
88 SDL_EventEntry *tail;
89 SDL_EventEntry *free;
90 SDL_SysWMEntry *wmmsg_used;
91 SDL_SysWMEntry *wmmsg_free;
92 } SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL };
93
94
95 /* 0 (default) means no logging, 1 means logging, 2 means logging with mouse and finger motion */
96 static int SDL_DoEventLogging = 0;
97
98 static void SDLCALL
SDL_EventLoggingChanged(void * userdata,const char * name,const char * oldValue,const char * hint)99 SDL_EventLoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
100 {
101 SDL_DoEventLogging = (hint && *hint) ? SDL_max(SDL_min(SDL_atoi(hint), 2), 0) : 0;
102 }
103
104 static void
SDL_LogEvent(const SDL_Event * event)105 SDL_LogEvent(const SDL_Event *event)
106 {
107 char name[32];
108 char details[128];
109
110 /* mouse/finger motion are spammy, ignore these if they aren't demanded. */
111 if ( (SDL_DoEventLogging < 2) &&
112 ( (event->type == SDL_MOUSEMOTION) ||
113 (event->type == SDL_FINGERMOTION) ) ) {
114 return;
115 }
116
117 /* this is to make SDL_snprintf() calls cleaner. */
118 #define uint unsigned int
119
120 name[0] = '\0';
121 details[0] = '\0';
122
123 /* !!! FIXME: This code is kinda ugly, sorry. */
124
125 if ((event->type >= SDL_USEREVENT) && (event->type <= SDL_LASTEVENT)) {
126 char plusstr[16];
127 SDL_strlcpy(name, "SDL_USEREVENT", sizeof (name));
128 if (event->type > SDL_USEREVENT) {
129 SDL_snprintf(plusstr, sizeof (plusstr), "+%u", ((uint) event->type) - SDL_USEREVENT);
130 } else {
131 plusstr[0] = '\0';
132 }
133 SDL_snprintf(details, sizeof (details), "%s (timestamp=%u windowid=%u code=%d data1=%p data2=%p)",
134 plusstr, (uint) event->user.timestamp, (uint) event->user.windowID,
135 (int) event->user.code, event->user.data1, event->user.data2);
136 }
137
138 switch (event->type) {
139 #define SDL_EVENT_CASE(x) case x: SDL_strlcpy(name, #x, sizeof (name));
140 SDL_EVENT_CASE(SDL_FIRSTEVENT) SDL_strlcpy(details, " (THIS IS PROBABLY A BUG!)", sizeof (details)); break;
141 SDL_EVENT_CASE(SDL_QUIT) SDL_snprintf(details, sizeof (details), " (timestamp=%u)", (uint) event->quit.timestamp); break;
142 SDL_EVENT_CASE(SDL_APP_TERMINATING) break;
143 SDL_EVENT_CASE(SDL_APP_LOWMEMORY) break;
144 SDL_EVENT_CASE(SDL_APP_WILLENTERBACKGROUND) break;
145 SDL_EVENT_CASE(SDL_APP_DIDENTERBACKGROUND) break;
146 SDL_EVENT_CASE(SDL_APP_WILLENTERFOREGROUND) break;
147 SDL_EVENT_CASE(SDL_APP_DIDENTERFOREGROUND) break;
148 SDL_EVENT_CASE(SDL_KEYMAPCHANGED) break;
149 SDL_EVENT_CASE(SDL_CLIPBOARDUPDATE) break;
150 SDL_EVENT_CASE(SDL_RENDER_TARGETS_RESET) break;
151 SDL_EVENT_CASE(SDL_RENDER_DEVICE_RESET) break;
152
153 SDL_EVENT_CASE(SDL_WINDOWEVENT) {
154 char name2[64];
155 switch(event->window.event) {
156 case SDL_WINDOWEVENT_NONE: SDL_strlcpy(name2, "SDL_WINDOWEVENT_NONE (THIS IS PROBABLY A BUG!)", sizeof (name2)); break;
157 #define SDL_WINDOWEVENT_CASE(x) case x: SDL_strlcpy(name2, #x, sizeof (name2)); break
158 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SHOWN);
159 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIDDEN);
160 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_EXPOSED);
161 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MOVED);
162 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESIZED);
163 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SIZE_CHANGED);
164 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MINIMIZED);
165 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MAXIMIZED);
166 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESTORED);
167 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_ENTER);
168 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_LEAVE);
169 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_GAINED);
170 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_LOST);
171 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_CLOSE);
172 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_TAKE_FOCUS);
173 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIT_TEST);
174 #undef SDL_WINDOWEVENT_CASE
175 default: SDL_strlcpy(name2, "UNKNOWN (bug? fixme?)", sizeof (name2)); break;
176 }
177 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u event=%s data1=%d data2=%d)",
178 (uint) event->window.timestamp, (uint) event->window.windowID, name2, (int) event->window.data1, (int) event->window.data2);
179 break;
180 }
181
182 SDL_EVENT_CASE(SDL_SYSWMEVENT)
183 /* !!! FIXME: we don't delve further at the moment. */
184 SDL_snprintf(details, sizeof (details), " (timestamp=%u)", (uint) event->syswm.timestamp);
185 break;
186
187 #define PRINT_KEY_EVENT(event) \
188 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \
189 (uint) event->key.timestamp, (uint) event->key.windowID, \
190 event->key.state == SDL_PRESSED ? "pressed" : "released", \
191 event->key.repeat ? "true" : "false", \
192 (uint) event->key.keysym.scancode, \
193 (uint) event->key.keysym.sym, \
194 (uint) event->key.keysym.mod)
195 SDL_EVENT_CASE(SDL_KEYDOWN) PRINT_KEY_EVENT(event); break;
196 SDL_EVENT_CASE(SDL_KEYUP) PRINT_KEY_EVENT(event); break;
197 #undef PRINT_KEY_EVENT
198
199 SDL_EVENT_CASE(SDL_TEXTEDITING)
200 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s' start=%d length=%d)",
201 (uint) event->edit.timestamp, (uint) event->edit.windowID,
202 event->edit.text, (int) event->edit.start, (int) event->edit.length);
203 break;
204
205 SDL_EVENT_CASE(SDL_TEXTINPUT)
206 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s')", (uint) event->text.timestamp, (uint) event->text.windowID, event->text.text);
207 break;
208
209
210 SDL_EVENT_CASE(SDL_MOUSEMOTION)
211 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u state=%u x=%d y=%d xrel=%d yrel=%d)",
212 (uint) event->motion.timestamp, (uint) event->motion.windowID,
213 (uint) event->motion.which, (uint) event->motion.state,
214 (int) event->motion.x, (int) event->motion.y,
215 (int) event->motion.xrel, (int) event->motion.yrel);
216 break;
217
218 #define PRINT_MBUTTON_EVENT(event) \
219 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%d y=%d)", \
220 (uint) event->button.timestamp, (uint) event->button.windowID, \
221 (uint) event->button.which, (uint) event->button.button, \
222 event->button.state == SDL_PRESSED ? "pressed" : "released", \
223 (uint) event->button.clicks, (int) event->button.x, (int) event->button.y)
224 SDL_EVENT_CASE(SDL_MOUSEBUTTONDOWN) PRINT_MBUTTON_EVENT(event); break;
225 SDL_EVENT_CASE(SDL_MOUSEBUTTONUP) PRINT_MBUTTON_EVENT(event); break;
226 #undef PRINT_MBUTTON_EVENT
227
228
229 SDL_EVENT_CASE(SDL_MOUSEWHEEL)
230 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u x=%d y=%d direction=%s)",
231 (uint) event->wheel.timestamp, (uint) event->wheel.windowID,
232 (uint) event->wheel.which, (int) event->wheel.x, (int) event->wheel.y,
233 event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
234 break;
235
236 SDL_EVENT_CASE(SDL_JOYAXISMOTION)
237 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)",
238 (uint) event->jaxis.timestamp, (int) event->jaxis.which,
239 (uint) event->jaxis.axis, (int) event->jaxis.value);
240 break;
241
242 SDL_EVENT_CASE(SDL_JOYBALLMOTION)
243 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)",
244 (uint) event->jball.timestamp, (int) event->jball.which,
245 (uint) event->jball.ball, (int) event->jball.xrel, (int) event->jball.yrel);
246 break;
247
248 SDL_EVENT_CASE(SDL_JOYHATMOTION)
249 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d hat=%u value=%u)",
250 (uint) event->jhat.timestamp, (int) event->jhat.which,
251 (uint) event->jhat.hat, (uint) event->jhat.value);
252 break;
253
254 #define PRINT_JBUTTON_EVENT(event) \
255 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \
256 (uint) event->jbutton.timestamp, (int) event->jbutton.which, \
257 (uint) event->jbutton.button, event->jbutton.state == SDL_PRESSED ? "pressed" : "released")
258 SDL_EVENT_CASE(SDL_JOYBUTTONDOWN) PRINT_JBUTTON_EVENT(event); break;
259 SDL_EVENT_CASE(SDL_JOYBUTTONUP) PRINT_JBUTTON_EVENT(event); break;
260 #undef PRINT_JBUTTON_EVENT
261
262 #define PRINT_JOYDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->jdevice.timestamp, (int) event->jdevice.which)
263 SDL_EVENT_CASE(SDL_JOYDEVICEADDED) PRINT_JOYDEV_EVENT(event); break;
264 SDL_EVENT_CASE(SDL_JOYDEVICEREMOVED) PRINT_JOYDEV_EVENT(event); break;
265 #undef PRINT_JOYDEV_EVENT
266
267 SDL_EVENT_CASE(SDL_CONTROLLERAXISMOTION)
268 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)",
269 (uint) event->caxis.timestamp, (int) event->caxis.which,
270 (uint) event->caxis.axis, (int) event->caxis.value);
271 break;
272
273 #define PRINT_CBUTTON_EVENT(event) \
274 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \
275 (uint) event->cbutton.timestamp, (int) event->cbutton.which, \
276 (uint) event->cbutton.button, event->cbutton.state == SDL_PRESSED ? "pressed" : "released")
277 SDL_EVENT_CASE(SDL_CONTROLLERBUTTONDOWN) PRINT_CBUTTON_EVENT(event); break;
278 SDL_EVENT_CASE(SDL_CONTROLLERBUTTONUP) PRINT_CBUTTON_EVENT(event); break;
279 #undef PRINT_CBUTTON_EVENT
280
281 #define PRINT_CONTROLLERDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->cdevice.timestamp, (int) event->cdevice.which)
282 SDL_EVENT_CASE(SDL_CONTROLLERDEVICEADDED) PRINT_CONTROLLERDEV_EVENT(event); break;
283 SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMOVED) PRINT_CONTROLLERDEV_EVENT(event); break;
284 SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMAPPED) PRINT_CONTROLLERDEV_EVENT(event); break;
285 #undef PRINT_CONTROLLERDEV_EVENT
286
287 #define PRINT_FINGER_EVENT(event) \
288 SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" fingerid=%"SDL_PRIs64" x=%f y=%f dx=%f dy=%f pressure=%f)", \
289 (uint) event->tfinger.timestamp, (long long)event->tfinger.touchId, \
290 (long long)event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \
291 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure)
292 SDL_EVENT_CASE(SDL_FINGERDOWN) PRINT_FINGER_EVENT(event); break;
293 SDL_EVENT_CASE(SDL_FINGERUP) PRINT_FINGER_EVENT(event); break;
294 SDL_EVENT_CASE(SDL_FINGERMOTION) PRINT_FINGER_EVENT(event); break;
295 #undef PRINT_FINGER_EVENT
296
297 #define PRINT_DOLLAR_EVENT(event) \
298 SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" gestureid=%"SDL_PRIs64" numfingers=%u error=%f x=%f y=%f)", \
299 (uint) event->dgesture.timestamp, (long long)event->dgesture.touchId, \
300 (long long)event->dgesture.gestureId, (uint) event->dgesture.numFingers, \
301 event->dgesture.error, event->dgesture.x, event->dgesture.y);
302 SDL_EVENT_CASE(SDL_DOLLARGESTURE) PRINT_DOLLAR_EVENT(event); break;
303 SDL_EVENT_CASE(SDL_DOLLARRECORD) PRINT_DOLLAR_EVENT(event); break;
304 #undef PRINT_DOLLAR_EVENT
305
306 SDL_EVENT_CASE(SDL_MULTIGESTURE)
307 SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" dtheta=%f ddist=%f x=%f y=%f numfingers=%u)",
308 (uint) event->mgesture.timestamp, (long long)event->mgesture.touchId,
309 event->mgesture.dTheta, event->mgesture.dDist,
310 event->mgesture.x, event->mgesture.y, (uint) event->mgesture.numFingers);
311 break;
312
313 #define PRINT_DROP_EVENT(event) SDL_snprintf(details, sizeof (details), " (file='%s' timestamp=%u windowid=%u)", event->drop.file, (uint) event->drop.timestamp, (uint) event->drop.windowID)
314 SDL_EVENT_CASE(SDL_DROPFILE) PRINT_DROP_EVENT(event); break;
315 SDL_EVENT_CASE(SDL_DROPTEXT) PRINT_DROP_EVENT(event); break;
316 SDL_EVENT_CASE(SDL_DROPBEGIN) PRINT_DROP_EVENT(event); break;
317 SDL_EVENT_CASE(SDL_DROPCOMPLETE) PRINT_DROP_EVENT(event); break;
318 #undef PRINT_DROP_EVENT
319
320 #define PRINT_AUDIODEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%u iscapture=%s)", (uint) event->adevice.timestamp, (uint) event->adevice.which, event->adevice.iscapture ? "true" : "false");
321 SDL_EVENT_CASE(SDL_AUDIODEVICEADDED) PRINT_AUDIODEV_EVENT(event); break;
322 SDL_EVENT_CASE(SDL_AUDIODEVICEREMOVED) PRINT_AUDIODEV_EVENT(event); break;
323 #undef PRINT_AUDIODEV_EVENT
324
325 #undef SDL_EVENT_CASE
326
327 default:
328 if (!name[0]) {
329 SDL_strlcpy(name, "UNKNOWN", sizeof (name));
330 SDL_snprintf(details, sizeof (details), " #%u! (Bug? FIXME?)", (uint) event->type);
331 }
332 break;
333 }
334
335 if (name[0]) {
336 SDL_Log("SDL EVENT: %s%s", name, details);
337 }
338
339 #undef uint
340 }
341
342
343
344 /* Public functions */
345
346 void
SDL_StopEventLoop(void)347 SDL_StopEventLoop(void)
348 {
349 const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
350 int i;
351 SDL_EventEntry *entry;
352 SDL_SysWMEntry *wmmsg;
353
354 if (SDL_EventQ.lock) {
355 SDL_LockMutex(SDL_EventQ.lock);
356 }
357
358 SDL_AtomicSet(&SDL_EventQ.active, 0);
359
360 if (report && SDL_atoi(report)) {
361 SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n",
362 SDL_EventQ.max_events_seen);
363 }
364
365 /* Clean out EventQ */
366 for (entry = SDL_EventQ.head; entry; ) {
367 SDL_EventEntry *next = entry->next;
368 SDL_free(entry);
369 entry = next;
370 }
371 for (entry = SDL_EventQ.free; entry; ) {
372 SDL_EventEntry *next = entry->next;
373 SDL_free(entry);
374 entry = next;
375 }
376 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
377 SDL_SysWMEntry *next = wmmsg->next;
378 SDL_free(wmmsg);
379 wmmsg = next;
380 }
381 for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
382 SDL_SysWMEntry *next = wmmsg->next;
383 SDL_free(wmmsg);
384 wmmsg = next;
385 }
386
387 SDL_AtomicSet(&SDL_EventQ.count, 0);
388 SDL_EventQ.max_events_seen = 0;
389 SDL_EventQ.head = NULL;
390 SDL_EventQ.tail = NULL;
391 SDL_EventQ.free = NULL;
392 SDL_EventQ.wmmsg_used = NULL;
393 SDL_EventQ.wmmsg_free = NULL;
394
395 /* Clear disabled event state */
396 for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
397 SDL_free(SDL_disabled_events[i]);
398 SDL_disabled_events[i] = NULL;
399 }
400
401 if (SDL_event_watchers_lock) {
402 SDL_DestroyMutex(SDL_event_watchers_lock);
403 SDL_event_watchers_lock = NULL;
404 }
405 if (SDL_event_watchers) {
406 SDL_free(SDL_event_watchers);
407 SDL_event_watchers = NULL;
408 SDL_event_watchers_count = 0;
409 }
410 SDL_zero(SDL_EventOK);
411
412 if (SDL_EventQ.lock) {
413 SDL_UnlockMutex(SDL_EventQ.lock);
414 SDL_DestroyMutex(SDL_EventQ.lock);
415 SDL_EventQ.lock = NULL;
416 }
417 }
418
419 /* This function (and associated calls) may be called more than once */
420 int
SDL_StartEventLoop(void)421 SDL_StartEventLoop(void)
422 {
423 /* We'll leave the event queue alone, since we might have gotten
424 some important events at launch (like SDL_DROPFILE)
425
426 FIXME: Does this introduce any other bugs with events at startup?
427 */
428
429 /* Create the lock and set ourselves active */
430 #if !SDL_THREADS_DISABLED
431 if (!SDL_EventQ.lock) {
432 SDL_EventQ.lock = SDL_CreateMutex();
433 if (SDL_EventQ.lock == NULL) {
434 return -1;
435 }
436 }
437
438 if (!SDL_event_watchers_lock) {
439 SDL_event_watchers_lock = SDL_CreateMutex();
440 if (SDL_event_watchers_lock == NULL) {
441 return -1;
442 }
443 }
444 #endif /* !SDL_THREADS_DISABLED */
445
446 /* Process most event types */
447 SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
448 SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
449 SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
450 #if 0 /* Leave these events enabled so apps can respond to items being dragged onto them at startup */
451 SDL_EventState(SDL_DROPFILE, SDL_DISABLE);
452 SDL_EventState(SDL_DROPTEXT, SDL_DISABLE);
453 #endif
454
455 SDL_AtomicSet(&SDL_EventQ.active, 1);
456
457 return 0;
458 }
459
460
461 /* Add an event to the event queue -- called with the queue locked */
462 static int
SDL_AddEvent(SDL_Event * event)463 SDL_AddEvent(SDL_Event * event)
464 {
465 SDL_EventEntry *entry;
466 const int initial_count = SDL_AtomicGet(&SDL_EventQ.count);
467 int final_count;
468
469 if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
470 SDL_SetError("Event queue is full (%d events)", initial_count);
471 return 0;
472 }
473
474 if (SDL_EventQ.free == NULL) {
475 entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
476 if (!entry) {
477 return 0;
478 }
479 } else {
480 entry = SDL_EventQ.free;
481 SDL_EventQ.free = entry->next;
482 }
483
484 if (SDL_DoEventLogging) {
485 SDL_LogEvent(event);
486 }
487
488 entry->event = *event;
489 if (event->type == SDL_SYSWMEVENT) {
490 entry->msg = *event->syswm.msg;
491 entry->event.syswm.msg = &entry->msg;
492 }
493
494 if (SDL_EventQ.tail) {
495 SDL_EventQ.tail->next = entry;
496 entry->prev = SDL_EventQ.tail;
497 SDL_EventQ.tail = entry;
498 entry->next = NULL;
499 } else {
500 SDL_assert(!SDL_EventQ.head);
501 SDL_EventQ.head = entry;
502 SDL_EventQ.tail = entry;
503 entry->prev = NULL;
504 entry->next = NULL;
505 }
506
507 final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1;
508 if (final_count > SDL_EventQ.max_events_seen) {
509 SDL_EventQ.max_events_seen = final_count;
510 }
511
512 return 1;
513 }
514
515 /* Remove an event from the queue -- called with the queue locked */
516 static void
SDL_CutEvent(SDL_EventEntry * entry)517 SDL_CutEvent(SDL_EventEntry *entry)
518 {
519 if (entry->prev) {
520 entry->prev->next = entry->next;
521 }
522 if (entry->next) {
523 entry->next->prev = entry->prev;
524 }
525
526 if (entry == SDL_EventQ.head) {
527 SDL_assert(entry->prev == NULL);
528 SDL_EventQ.head = entry->next;
529 }
530 if (entry == SDL_EventQ.tail) {
531 SDL_assert(entry->next == NULL);
532 SDL_EventQ.tail = entry->prev;
533 }
534
535 entry->next = SDL_EventQ.free;
536 SDL_EventQ.free = entry;
537 SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0);
538 SDL_AtomicAdd(&SDL_EventQ.count, -1);
539 }
540
541 /* Lock the event queue, take a peep at it, and unlock it */
542 int
SDL_PeepEvents(SDL_Event * events,int numevents,SDL_eventaction action,Uint32 minType,Uint32 maxType)543 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
544 Uint32 minType, Uint32 maxType)
545 {
546 int i, used;
547
548 /* Don't look after we've quit */
549 if (!SDL_AtomicGet(&SDL_EventQ.active)) {
550 /* We get a few spurious events at shutdown, so don't warn then */
551 if (action != SDL_ADDEVENT) {
552 SDL_SetError("The event system has been shut down");
553 }
554 return (-1);
555 }
556 /* Lock the event queue */
557 used = 0;
558 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
559 if (action == SDL_ADDEVENT) {
560 for (i = 0; i < numevents; ++i) {
561 used += SDL_AddEvent(&events[i]);
562 }
563 } else {
564 SDL_EventEntry *entry, *next;
565 SDL_SysWMEntry *wmmsg, *wmmsg_next;
566 Uint32 type;
567
568 if (action == SDL_GETEVENT) {
569 /* Clean out any used wmmsg data
570 FIXME: Do we want to retain the data for some period of time?
571 */
572 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
573 wmmsg_next = wmmsg->next;
574 wmmsg->next = SDL_EventQ.wmmsg_free;
575 SDL_EventQ.wmmsg_free = wmmsg;
576 }
577 SDL_EventQ.wmmsg_used = NULL;
578 }
579
580 for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) {
581 next = entry->next;
582 type = entry->event.type;
583 if (minType <= type && type <= maxType) {
584 if (events) {
585 events[used] = entry->event;
586 if (entry->event.type == SDL_SYSWMEVENT) {
587 /* We need to copy the wmmsg somewhere safe.
588 For now we'll guarantee it's valid at least until
589 the next call to SDL_PeepEvents()
590 */
591 if (SDL_EventQ.wmmsg_free) {
592 wmmsg = SDL_EventQ.wmmsg_free;
593 SDL_EventQ.wmmsg_free = wmmsg->next;
594 } else {
595 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
596 }
597 wmmsg->msg = *entry->event.syswm.msg;
598 wmmsg->next = SDL_EventQ.wmmsg_used;
599 SDL_EventQ.wmmsg_used = wmmsg;
600 events[used].syswm.msg = &wmmsg->msg;
601 }
602
603 if (action == SDL_GETEVENT) {
604 SDL_CutEvent(entry);
605 }
606 }
607 ++used;
608 }
609 }
610 }
611 if (SDL_EventQ.lock) {
612 SDL_UnlockMutex(SDL_EventQ.lock);
613 }
614 } else {
615 return SDL_SetError("Couldn't lock event queue");
616 }
617 return (used);
618 }
619
620 SDL_bool
SDL_HasEvent(Uint32 type)621 SDL_HasEvent(Uint32 type)
622 {
623 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
624 }
625
626 SDL_bool
SDL_HasEvents(Uint32 minType,Uint32 maxType)627 SDL_HasEvents(Uint32 minType, Uint32 maxType)
628 {
629 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
630 }
631
632 void
SDL_FlushEvent(Uint32 type)633 SDL_FlushEvent(Uint32 type)
634 {
635 SDL_FlushEvents(type, type);
636 }
637
638 void
SDL_FlushEvents(Uint32 minType,Uint32 maxType)639 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
640 {
641 /* !!! FIXME: we need to manually SDL_free() the strings in TEXTINPUT and
642 drag'n'drop events if we're flushing them without passing them to the
643 app, but I don't know if this is the right place to do that. */
644
645 /* Don't look after we've quit */
646 if (!SDL_AtomicGet(&SDL_EventQ.active)) {
647 return;
648 }
649
650 /* Make sure the events are current */
651 #if 0
652 /* Actually, we can't do this since we might be flushing while processing
653 a resize event, and calling this might trigger further resize events.
654 */
655 SDL_PumpEvents();
656 #endif
657
658 /* Lock the event queue */
659 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
660 SDL_EventEntry *entry, *next;
661 Uint32 type;
662 for (entry = SDL_EventQ.head; entry; entry = next) {
663 next = entry->next;
664 type = entry->event.type;
665 if (minType <= type && type <= maxType) {
666 SDL_CutEvent(entry);
667 }
668 }
669 if (SDL_EventQ.lock) {
670 SDL_UnlockMutex(SDL_EventQ.lock);
671 }
672 }
673 }
674
675 /* Run the system dependent event loops */
676 void
SDL_PumpEvents(void)677 SDL_PumpEvents(void)
678 {
679 SDL_VideoDevice *_this = SDL_GetVideoDevice();
680
681 /* Release any keys held down from last frame */
682 SDL_ReleaseAutoReleaseKeys();
683
684 /* Get events from the video subsystem */
685 if (_this) {
686 _this->PumpEvents(_this);
687 }
688
689 #if !SDL_JOYSTICK_DISABLED
690 /* Check for joystick state change */
691 if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
692 SDL_JoystickUpdate();
693 }
694 #endif
695
696 #if !SDL_SENSOR_DISABLED
697 /* Check for sensor state change */
698 if (!SDL_disabled_events[SDL_SENSORUPDATE >> 8]) {
699 SDL_SensorUpdate();
700 }
701 #endif
702
703 SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
704 }
705
706 /* Public functions */
707
708 int
SDL_PollEvent(SDL_Event * event)709 SDL_PollEvent(SDL_Event * event)
710 {
711 return SDL_WaitEventTimeout(event, 0);
712 }
713
714 int
SDL_WaitEvent(SDL_Event * event)715 SDL_WaitEvent(SDL_Event * event)
716 {
717 return SDL_WaitEventTimeout(event, -1);
718 }
719
720 int
SDL_WaitEventTimeout(SDL_Event * event,int timeout)721 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
722 {
723 Uint32 expiration = 0;
724
725 if (timeout > 0)
726 expiration = SDL_GetTicks() + timeout;
727
728 for (;;) {
729 SDL_PumpEvents();
730 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
731 case -1:
732 return 0;
733 case 0:
734 if (timeout == 0) {
735 /* Polling and no events, just return */
736 return 0;
737 }
738 if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
739 /* Timeout expired and no events */
740 return 0;
741 }
742 SDL_Delay(1);
743 break;
744 default:
745 /* Has events */
746 return 1;
747 }
748 }
749 }
750
751 int
SDL_PushEvent(SDL_Event * event)752 SDL_PushEvent(SDL_Event * event)
753 {
754 event->common.timestamp = SDL_GetTicks();
755
756 if (SDL_EventOK.callback || SDL_event_watchers_count > 0) {
757 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
758 if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) {
759 if (SDL_event_watchers_lock) {
760 SDL_UnlockMutex(SDL_event_watchers_lock);
761 }
762 return 0;
763 }
764
765 if (SDL_event_watchers_count > 0) {
766 /* Make sure we only dispatch the current watcher list */
767 int i, event_watchers_count = SDL_event_watchers_count;
768
769 SDL_event_watchers_dispatching = SDL_TRUE;
770 for (i = 0; i < event_watchers_count; ++i) {
771 if (!SDL_event_watchers[i].removed) {
772 SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event);
773 }
774 }
775 SDL_event_watchers_dispatching = SDL_FALSE;
776
777 if (SDL_event_watchers_removed) {
778 for (i = SDL_event_watchers_count; i--; ) {
779 if (SDL_event_watchers[i].removed) {
780 --SDL_event_watchers_count;
781 if (i < SDL_event_watchers_count) {
782 SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
783 }
784 }
785 }
786 SDL_event_watchers_removed = SDL_FALSE;
787 }
788 }
789
790 if (SDL_event_watchers_lock) {
791 SDL_UnlockMutex(SDL_event_watchers_lock);
792 }
793 }
794 }
795
796 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
797 return -1;
798 }
799
800 SDL_GestureProcessEvent(event);
801
802 return 1;
803 }
804
805 void
SDL_SetEventFilter(SDL_EventFilter filter,void * userdata)806 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
807 {
808 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
809 /* Set filter and discard pending events */
810 SDL_EventOK.callback = filter;
811 SDL_EventOK.userdata = userdata;
812 SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
813
814 if (SDL_event_watchers_lock) {
815 SDL_UnlockMutex(SDL_event_watchers_lock);
816 }
817 }
818 }
819
820 SDL_bool
SDL_GetEventFilter(SDL_EventFilter * filter,void ** userdata)821 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
822 {
823 SDL_EventWatcher event_ok;
824
825 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
826 event_ok = SDL_EventOK;
827
828 if (SDL_event_watchers_lock) {
829 SDL_UnlockMutex(SDL_event_watchers_lock);
830 }
831 } else {
832 SDL_zero(event_ok);
833 }
834
835 if (filter) {
836 *filter = event_ok.callback;
837 }
838 if (userdata) {
839 *userdata = event_ok.userdata;
840 }
841 return event_ok.callback ? SDL_TRUE : SDL_FALSE;
842 }
843
844 void
SDL_AddEventWatch(SDL_EventFilter filter,void * userdata)845 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
846 {
847 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
848 SDL_EventWatcher *event_watchers;
849
850 event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
851 if (event_watchers) {
852 SDL_EventWatcher *watcher;
853
854 SDL_event_watchers = event_watchers;
855 watcher = &SDL_event_watchers[SDL_event_watchers_count];
856 watcher->callback = filter;
857 watcher->userdata = userdata;
858 watcher->removed = SDL_FALSE;
859 ++SDL_event_watchers_count;
860 }
861
862 if (SDL_event_watchers_lock) {
863 SDL_UnlockMutex(SDL_event_watchers_lock);
864 }
865 }
866 }
867
868 void
SDL_DelEventWatch(SDL_EventFilter filter,void * userdata)869 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
870 {
871 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
872 int i;
873
874 for (i = 0; i < SDL_event_watchers_count; ++i) {
875 if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) {
876 if (SDL_event_watchers_dispatching) {
877 SDL_event_watchers[i].removed = SDL_TRUE;
878 SDL_event_watchers_removed = SDL_TRUE;
879 } else {
880 --SDL_event_watchers_count;
881 if (i < SDL_event_watchers_count) {
882 SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
883 }
884 }
885 break;
886 }
887 }
888
889 if (SDL_event_watchers_lock) {
890 SDL_UnlockMutex(SDL_event_watchers_lock);
891 }
892 }
893 }
894
895 void
SDL_FilterEvents(SDL_EventFilter filter,void * userdata)896 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
897 {
898 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
899 SDL_EventEntry *entry, *next;
900 for (entry = SDL_EventQ.head; entry; entry = next) {
901 next = entry->next;
902 if (!filter(userdata, &entry->event)) {
903 SDL_CutEvent(entry);
904 }
905 }
906 if (SDL_EventQ.lock) {
907 SDL_UnlockMutex(SDL_EventQ.lock);
908 }
909 }
910 }
911
912 Uint8
SDL_EventState(Uint32 type,int state)913 SDL_EventState(Uint32 type, int state)
914 {
915 const SDL_bool isdnd = ((state == SDL_DISABLE) || (state == SDL_ENABLE)) &&
916 ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT));
917 Uint8 current_state;
918 Uint8 hi = ((type >> 8) & 0xff);
919 Uint8 lo = (type & 0xff);
920
921 if (SDL_disabled_events[hi] &&
922 (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
923 current_state = SDL_DISABLE;
924 } else {
925 current_state = SDL_ENABLE;
926 }
927
928 if (state != current_state)
929 {
930 switch (state) {
931 case SDL_DISABLE:
932 /* Disable this event type and discard pending events */
933 if (!SDL_disabled_events[hi]) {
934 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
935 if (!SDL_disabled_events[hi]) {
936 /* Out of memory, nothing we can do... */
937 break;
938 }
939 }
940 SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
941 SDL_FlushEvent(type);
942 break;
943 case SDL_ENABLE:
944 SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
945 break;
946 default:
947 /* Querying state... */
948 break;
949 }
950 }
951
952 /* turn off drag'n'drop support if we've disabled the events.
953 This might change some UI details at the OS level. */
954 if (isdnd) {
955 SDL_ToggleDragAndDropSupport();
956 }
957
958 return current_state;
959 }
960
961 Uint32
SDL_RegisterEvents(int numevents)962 SDL_RegisterEvents(int numevents)
963 {
964 Uint32 event_base;
965
966 if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
967 event_base = SDL_userevents;
968 SDL_userevents += numevents;
969 } else {
970 event_base = (Uint32)-1;
971 }
972 return event_base;
973 }
974
975 int
SDL_SendAppEvent(SDL_EventType eventType)976 SDL_SendAppEvent(SDL_EventType eventType)
977 {
978 int posted;
979
980 posted = 0;
981 if (SDL_GetEventState(eventType) == SDL_ENABLE) {
982 SDL_Event event;
983 event.type = eventType;
984 posted = (SDL_PushEvent(&event) > 0);
985 }
986 return (posted);
987 }
988
989 int
SDL_SendSysWMEvent(SDL_SysWMmsg * message)990 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
991 {
992 int posted;
993
994 posted = 0;
995 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
996 SDL_Event event;
997 SDL_memset(&event, 0, sizeof(event));
998 event.type = SDL_SYSWMEVENT;
999 event.syswm.msg = message;
1000 posted = (SDL_PushEvent(&event) > 0);
1001 }
1002 /* Update internal event state */
1003 return (posted);
1004 }
1005
1006 int
SDL_SendKeymapChangedEvent(void)1007 SDL_SendKeymapChangedEvent(void)
1008 {
1009 return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
1010 }
1011
1012 int
SDL_SendLocaleChangedEvent(void)1013 SDL_SendLocaleChangedEvent(void)
1014 {
1015 return SDL_SendAppEvent(SDL_LOCALECHANGED);
1016 }
1017
1018 int
SDL_EventsInit(void)1019 SDL_EventsInit(void)
1020 {
1021 SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1022 if (SDL_StartEventLoop() < 0) {
1023 SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1024 return -1;
1025 }
1026
1027 SDL_QuitInit();
1028
1029 return 0;
1030 }
1031
1032 void
SDL_EventsQuit(void)1033 SDL_EventsQuit(void)
1034 {
1035 SDL_QuitQuit();
1036 SDL_StopEventLoop();
1037 SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1038 }
1039
1040 /* vi: set ts=4 sw=4 expandtab: */
1041