2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../SDL_internal.h"
23 /* General event handling code for SDL */
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"
33 #include "../video/SDL_sysvideo.h"
34 #include "SDL_syswm.h"
38 #define SDL_PRIs64 "I64d"
40 #define SDL_PRIs64 "lld"
43 /* An arbitrary limit so we don't have unbounded growth */
44 #define SDL_MAX_QUEUED_EVENTS 65535
46 typedef struct SDL_EventWatcher {
47 SDL_EventFilter callback;
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;
61 } SDL_DisabledEventBlock;
63 static SDL_DisabledEventBlock *SDL_disabled_events[256];
64 static Uint32 SDL_userevents = SDL_USEREVENT;
66 /* Private data -- event queue */
67 typedef struct _SDL_EventEntry
71 struct _SDL_EventEntry *prev;
72 struct _SDL_EventEntry *next;
75 typedef struct _SDL_SysWMEntry
78 struct _SDL_SysWMEntry *next;
90 SDL_SysWMEntry *wmmsg_used;
91 SDL_SysWMEntry *wmmsg_free;
92 } SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL };
95 #if !SDL_JOYSTICK_DISABLED
97 static SDL_bool SDL_update_joysticks = SDL_TRUE;
100 SDL_CalculateShouldUpdateJoysticks()
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;
106 SDL_update_joysticks = SDL_FALSE;
111 SDL_AutoUpdateJoysticksChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
113 SDL_CalculateShouldUpdateJoysticks();
116 #endif /* !SDL_JOYSTICK_DISABLED */
119 #if !SDL_SENSOR_DISABLED
121 static SDL_bool SDL_update_sensors = SDL_TRUE;
124 SDL_CalculateShouldUpdateSensors()
126 if (SDL_GetHintBoolean(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_TRUE) &&
127 !SDL_disabled_events[SDL_SENSORUPDATE >> 8]) {
128 SDL_update_sensors = SDL_TRUE;
130 SDL_update_sensors = SDL_FALSE;
135 SDL_AutoUpdateSensorsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
137 SDL_CalculateShouldUpdateSensors();
140 #endif /* !SDL_SENSOR_DISABLED */
143 /* 0 (default) means no logging, 1 means logging, 2 means logging with mouse and finger motion */
144 static int SDL_DoEventLogging = 0;
147 SDL_EventLoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
149 SDL_DoEventLogging = (hint && *hint) ? SDL_max(SDL_min(SDL_atoi(hint), 2), 0) : 0;
153 SDL_LogEvent(const SDL_Event *event)
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) ) ) {
165 /* this is to make SDL_snprintf() calls cleaner. */
166 #define uint unsigned int
171 /* !!! FIXME: This code is kinda ugly, sorry. */
173 if ((event->type >= SDL_USEREVENT) && (event->type <= SDL_LASTEVENT)) {
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);
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);
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;
201 SDL_EVENT_CASE(SDL_WINDOWEVENT) {
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;
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);
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);
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
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);
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);
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);
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
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");
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);
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);
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);
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
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
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);
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
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
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
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
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);
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
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
373 #undef SDL_EVENT_CASE
377 SDL_strlcpy(name, "UNKNOWN", sizeof (name));
378 SDL_snprintf(details, sizeof (details), " #%u! (Bug? FIXME?)", (uint) event->type);
384 SDL_Log("SDL EVENT: %s%s", name, details);
392 /* Public functions */
395 SDL_StopEventLoop(void)
397 const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
399 SDL_EventEntry *entry;
400 SDL_SysWMEntry *wmmsg;
402 if (SDL_EventQ.lock) {
403 SDL_LockMutex(SDL_EventQ.lock);
406 SDL_AtomicSet(&SDL_EventQ.active, 0);
408 if (report && SDL_atoi(report)) {
409 SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n",
410 SDL_EventQ.max_events_seen);
413 /* Clean out EventQ */
414 for (entry = SDL_EventQ.head; entry; ) {
415 SDL_EventEntry *next = entry->next;
419 for (entry = SDL_EventQ.free; entry; ) {
420 SDL_EventEntry *next = entry->next;
424 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
425 SDL_SysWMEntry *next = wmmsg->next;
429 for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
430 SDL_SysWMEntry *next = wmmsg->next;
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;
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;
449 if (SDL_event_watchers_lock) {
450 SDL_DestroyMutex(SDL_event_watchers_lock);
451 SDL_event_watchers_lock = NULL;
453 if (SDL_event_watchers) {
454 SDL_free(SDL_event_watchers);
455 SDL_event_watchers = NULL;
456 SDL_event_watchers_count = 0;
458 SDL_zero(SDL_EventOK);
460 if (SDL_EventQ.lock) {
461 SDL_UnlockMutex(SDL_EventQ.lock);
462 SDL_DestroyMutex(SDL_EventQ.lock);
463 SDL_EventQ.lock = NULL;
467 /* This function (and associated calls) may be called more than once */
469 SDL_StartEventLoop(void)
471 /* We'll leave the event queue alone, since we might have gotten
472 some important events at launch (like SDL_DROPFILE)
474 FIXME: Does this introduce any other bugs with events at startup?
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) {
486 if (!SDL_event_watchers_lock) {
487 SDL_event_watchers_lock = SDL_CreateMutex();
488 if (SDL_event_watchers_lock == NULL) {
492 #endif /* !SDL_THREADS_DISABLED */
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);
503 SDL_AtomicSet(&SDL_EventQ.active, 1);
509 /* Add an event to the event queue -- called with the queue locked */
511 SDL_AddEvent(SDL_Event * event)
513 SDL_EventEntry *entry;
514 const int initial_count = SDL_AtomicGet(&SDL_EventQ.count);
517 if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
518 SDL_SetError("Event queue is full (%d events)", initial_count);
522 if (SDL_EventQ.free == NULL) {
523 entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
528 entry = SDL_EventQ.free;
529 SDL_EventQ.free = entry->next;
532 if (SDL_DoEventLogging) {
536 entry->event = *event;
537 if (event->type == SDL_SYSWMEVENT) {
538 entry->msg = *event->syswm.msg;
539 entry->event.syswm.msg = &entry->msg;
542 if (SDL_EventQ.tail) {
543 SDL_EventQ.tail->next = entry;
544 entry->prev = SDL_EventQ.tail;
545 SDL_EventQ.tail = entry;
548 SDL_assert(!SDL_EventQ.head);
549 SDL_EventQ.head = entry;
550 SDL_EventQ.tail = entry;
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;
563 /* Remove an event from the queue -- called with the queue locked */
565 SDL_CutEvent(SDL_EventEntry *entry)
568 entry->prev->next = entry->next;
571 entry->next->prev = entry->prev;
574 if (entry == SDL_EventQ.head) {
575 SDL_assert(entry->prev == NULL);
576 SDL_EventQ.head = entry->next;
578 if (entry == SDL_EventQ.tail) {
579 SDL_assert(entry->next == NULL);
580 SDL_EventQ.tail = entry->prev;
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);
589 /* Lock the event queue, take a peep at it, and unlock it */
591 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
592 Uint32 minType, Uint32 maxType)
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");
604 /* Lock the event queue */
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]);
612 SDL_EventEntry *entry, *next;
613 SDL_SysWMEntry *wmmsg, *wmmsg_next;
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?
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;
625 SDL_EventQ.wmmsg_used = NULL;
628 for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) {
630 type = entry->event.type;
631 if (minType <= type && type <= maxType) {
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()
639 if (SDL_EventQ.wmmsg_free) {
640 wmmsg = SDL_EventQ.wmmsg_free;
641 SDL_EventQ.wmmsg_free = wmmsg->next;
643 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
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;
651 if (action == SDL_GETEVENT) {
659 if (SDL_EventQ.lock) {
660 SDL_UnlockMutex(SDL_EventQ.lock);
663 return SDL_SetError("Couldn't lock event queue");
669 SDL_HasEvent(Uint32 type)
671 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
675 SDL_HasEvents(Uint32 minType, Uint32 maxType)
677 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
681 SDL_FlushEvent(Uint32 type)
683 SDL_FlushEvents(type, type);
687 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
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. */
693 /* Don't look after we've quit */
694 if (!SDL_AtomicGet(&SDL_EventQ.active)) {
698 /* Make sure the events are current */
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.
706 /* Lock the event queue */
707 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
708 SDL_EventEntry *entry, *next;
710 for (entry = SDL_EventQ.head; entry; entry = next) {
712 type = entry->event.type;
713 if (minType <= type && type <= maxType) {
717 if (SDL_EventQ.lock) {
718 SDL_UnlockMutex(SDL_EventQ.lock);
723 /* Run the system dependent event loops */
727 SDL_VideoDevice *_this = SDL_GetVideoDevice();
729 /* Release any keys held down from last frame */
730 SDL_ReleaseAutoReleaseKeys();
732 /* Get events from the video subsystem */
734 _this->PumpEvents(_this);
737 #if !SDL_JOYSTICK_DISABLED
738 /* Check for joystick state change */
739 if (SDL_update_joysticks) {
740 SDL_JoystickUpdate();
744 #if !SDL_SENSOR_DISABLED
745 /* Check for sensor state change */
746 if (SDL_update_sensors) {
751 SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
754 /* Public functions */
757 SDL_PollEvent(SDL_Event * event)
759 return SDL_WaitEventTimeout(event, 0);
763 SDL_WaitEvent(SDL_Event * event)
765 return SDL_WaitEventTimeout(event, -1);
769 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
771 Uint32 expiration = 0;
774 expiration = SDL_GetTicks() + timeout;
778 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
783 /* Polling and no events, just return */
786 if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
787 /* Timeout expired and no events */
800 SDL_PushEvent(SDL_Event * event)
802 event->common.timestamp = SDL_GetTicks();
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);
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;
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);
823 SDL_event_watchers_dispatching = SDL_FALSE;
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]));
834 SDL_event_watchers_removed = SDL_FALSE;
838 if (SDL_event_watchers_lock) {
839 SDL_UnlockMutex(SDL_event_watchers_lock);
844 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
848 SDL_GestureProcessEvent(event);
854 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
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);
862 if (SDL_event_watchers_lock) {
863 SDL_UnlockMutex(SDL_event_watchers_lock);
869 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
871 SDL_EventWatcher event_ok;
873 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
874 event_ok = SDL_EventOK;
876 if (SDL_event_watchers_lock) {
877 SDL_UnlockMutex(SDL_event_watchers_lock);
884 *filter = event_ok.callback;
887 *userdata = event_ok.userdata;
889 return event_ok.callback ? SDL_TRUE : SDL_FALSE;
893 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
895 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
896 SDL_EventWatcher *event_watchers;
898 event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
899 if (event_watchers) {
900 SDL_EventWatcher *watcher;
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;
910 if (SDL_event_watchers_lock) {
911 SDL_UnlockMutex(SDL_event_watchers_lock);
917 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
919 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
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;
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]));
937 if (SDL_event_watchers_lock) {
938 SDL_UnlockMutex(SDL_event_watchers_lock);
944 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
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) {
950 if (!filter(userdata, &entry->event)) {
954 if (SDL_EventQ.lock) {
955 SDL_UnlockMutex(SDL_EventQ.lock);
961 SDL_EventState(Uint32 type, int state)
963 const SDL_bool isdnd = ((state == SDL_DISABLE) || (state == SDL_ENABLE)) &&
964 ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT));
966 Uint8 hi = ((type >> 8) & 0xff);
967 Uint8 lo = (type & 0xff);
969 if (SDL_disabled_events[hi] &&
970 (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
971 current_state = SDL_DISABLE;
973 current_state = SDL_ENABLE;
976 if (state != current_state)
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... */
988 SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
989 SDL_FlushEvent(type);
992 SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
995 /* Querying state... */
999 #if !SDL_JOYSTICK_DISABLED
1000 if (state == SDL_DISABLE || state == SDL_ENABLE) {
1001 SDL_CalculateShouldUpdateJoysticks();
1004 #if !SDL_SENSOR_DISABLED
1005 if (state == SDL_DISABLE || state == SDL_ENABLE) {
1006 SDL_CalculateShouldUpdateSensors();
1011 /* turn off drag'n'drop support if we've disabled the events.
1012 This might change some UI details at the OS level. */
1014 SDL_ToggleDragAndDropSupport();
1017 return current_state;
1021 SDL_RegisterEvents(int numevents)
1025 if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
1026 event_base = SDL_userevents;
1027 SDL_userevents += numevents;
1029 event_base = (Uint32)-1;
1035 SDL_SendAppEvent(SDL_EventType eventType)
1040 if (SDL_GetEventState(eventType) == SDL_ENABLE) {
1042 event.type = eventType;
1043 posted = (SDL_PushEvent(&event) > 0);
1049 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
1054 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
1056 SDL_memset(&event, 0, sizeof(event));
1057 event.type = SDL_SYSWMEVENT;
1058 event.syswm.msg = message;
1059 posted = (SDL_PushEvent(&event) > 0);
1061 /* Update internal event state */
1066 SDL_SendKeymapChangedEvent(void)
1068 return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
1072 SDL_SendLocaleChangedEvent(void)
1074 return SDL_SendAppEvent(SDL_LOCALECHANGED);
1078 SDL_EventsInit(void)
1080 #if !SDL_JOYSTICK_DISABLED
1081 SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_JOYSTICKS, SDL_AutoUpdateJoysticksChanged, NULL);
1083 #if !SDL_SENSOR_DISABLED
1084 SDL_AddHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL);
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);
1098 SDL_EventsQuit(void)
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);
1106 #if !SDL_SENSOR_DISABLED
1107 SDL_DelHintCallback(SDL_HINT_AUTO_UPDATE_SENSORS, SDL_AutoUpdateSensorsChanged, NULL);
1111 /* vi: set ts=4 sw=4 expandtab: */