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