2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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"
36 /* An arbitrary limit so we don't have unbounded growth */
37 #define SDL_MAX_QUEUED_EVENTS 65535
39 typedef struct SDL_EventWatcher {
40 SDL_EventFilter callback;
45 static SDL_mutex *SDL_event_watchers_lock;
46 static SDL_EventWatcher SDL_EventOK;
47 static SDL_EventWatcher *SDL_event_watchers = NULL;
48 static int SDL_event_watchers_count = 0;
49 static SDL_bool SDL_event_watchers_dispatching = SDL_FALSE;
50 static SDL_bool SDL_event_watchers_removed = SDL_FALSE;
54 } SDL_DisabledEventBlock;
56 static SDL_DisabledEventBlock *SDL_disabled_events[256];
57 static Uint32 SDL_userevents = SDL_USEREVENT;
59 /* Private data -- event queue */
60 typedef struct _SDL_EventEntry
64 struct _SDL_EventEntry *prev;
65 struct _SDL_EventEntry *next;
68 typedef struct _SDL_SysWMEntry
71 struct _SDL_SysWMEntry *next;
83 SDL_SysWMEntry *wmmsg_used;
84 SDL_SysWMEntry *wmmsg_free;
85 } SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL };
88 /* 0 (default) means no logging, 1 means logging, 2 means logging with mouse and finger motion */
89 static int SDL_DoEventLogging = 0;
92 SDL_EventLoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
94 SDL_DoEventLogging = (hint && *hint) ? SDL_max(SDL_min(SDL_atoi(hint), 2), 0) : 0;
98 SDL_LogEvent(const SDL_Event *event)
103 /* mouse/finger motion are spammy, ignore these if they aren't demanded. */
104 if ( (SDL_DoEventLogging < 2) &&
105 ( (event->type == SDL_MOUSEMOTION) ||
106 (event->type == SDL_FINGERMOTION) ) ) {
110 /* this is to make SDL_snprintf() calls cleaner. */
111 #define uint unsigned int
116 /* !!! FIXME: This code is kinda ugly, sorry. */
118 if ((event->type >= SDL_USEREVENT) && (event->type <= SDL_LASTEVENT)) {
120 SDL_strlcpy(name, "SDL_USEREVENT", sizeof (name));
121 if (event->type > SDL_USEREVENT) {
122 SDL_snprintf(plusstr, sizeof (plusstr), "+%u", ((uint) event->type) - SDL_USEREVENT);
126 SDL_snprintf(details, sizeof (details), "%s (timestamp=%u windowid=%u code=%d data1=%p data2=%p)",
127 plusstr, (uint) event->user.timestamp, (uint) event->user.windowID,
128 (int) event->user.code, event->user.data1, event->user.data2);
131 switch (event->type) {
132 #define SDL_EVENT_CASE(x) case x: SDL_strlcpy(name, #x, sizeof (name));
133 SDL_EVENT_CASE(SDL_FIRSTEVENT) SDL_strlcpy(details, " (THIS IS PROBABLY A BUG!)", sizeof (details)); break;
134 SDL_EVENT_CASE(SDL_QUIT) SDL_snprintf(details, sizeof (details), " (timestamp=%u)", (uint) event->quit.timestamp); break;
135 SDL_EVENT_CASE(SDL_APP_TERMINATING) break;
136 SDL_EVENT_CASE(SDL_APP_LOWMEMORY) break;
137 SDL_EVENT_CASE(SDL_APP_WILLENTERBACKGROUND) break;
138 SDL_EVENT_CASE(SDL_APP_DIDENTERBACKGROUND) break;
139 SDL_EVENT_CASE(SDL_APP_WILLENTERFOREGROUND) break;
140 SDL_EVENT_CASE(SDL_APP_DIDENTERFOREGROUND) break;
141 SDL_EVENT_CASE(SDL_KEYMAPCHANGED) break;
142 SDL_EVENT_CASE(SDL_CLIPBOARDUPDATE) break;
143 SDL_EVENT_CASE(SDL_RENDER_TARGETS_RESET) break;
144 SDL_EVENT_CASE(SDL_RENDER_DEVICE_RESET) break;
146 SDL_EVENT_CASE(SDL_WINDOWEVENT) {
148 switch(event->window.event) {
149 case SDL_WINDOWEVENT_NONE: SDL_strlcpy(name2, "SDL_WINDOWEVENT_NONE (THIS IS PROBABLY A BUG!)", sizeof (name2)); break;
150 #define SDL_WINDOWEVENT_CASE(x) case x: SDL_strlcpy(name2, #x, sizeof (name2)); break
151 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SHOWN);
152 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIDDEN);
153 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_EXPOSED);
154 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MOVED);
155 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESIZED);
156 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_SIZE_CHANGED);
157 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MINIMIZED);
158 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_MAXIMIZED);
159 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_RESTORED);
160 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_ENTER);
161 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_LEAVE);
162 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_GAINED);
163 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_FOCUS_LOST);
164 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_CLOSE);
165 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_TAKE_FOCUS);
166 SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIT_TEST);
167 #undef SDL_WINDOWEVENT_CASE
168 default: SDL_strlcpy(name2, "UNKNOWN (bug? fixme?)", sizeof (name2)); break;
170 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u event=%s data1=%d data2=%d)",
171 (uint) event->window.timestamp, (uint) event->window.windowID, name2, (int) event->window.data1, (int) event->window.data2);
175 SDL_EVENT_CASE(SDL_SYSWMEVENT)
176 /* !!! FIXME: we don't delve further at the moment. */
177 SDL_snprintf(details, sizeof (details), " (timestamp=%u)", (uint) event->syswm.timestamp);
180 #define PRINT_KEY_EVENT(event) \
181 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u state=%s repeat=%s scancode=%u keycode=%u mod=%u)", \
182 (uint) event->key.timestamp, (uint) event->key.windowID, \
183 event->key.state == SDL_PRESSED ? "pressed" : "released", \
184 event->key.repeat ? "true" : "false", \
185 (uint) event->key.keysym.scancode, \
186 (uint) event->key.keysym.sym, \
187 (uint) event->key.keysym.mod)
188 SDL_EVENT_CASE(SDL_KEYDOWN) PRINT_KEY_EVENT(event); break;
189 SDL_EVENT_CASE(SDL_KEYUP) PRINT_KEY_EVENT(event); break;
190 #undef PRINT_KEY_EVENT
192 SDL_EVENT_CASE(SDL_TEXTEDITING)
193 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s' start=%d length=%d)",
194 (uint) event->edit.timestamp, (uint) event->edit.windowID,
195 event->edit.text, (int) event->edit.start, (int) event->edit.length);
198 SDL_EVENT_CASE(SDL_TEXTINPUT)
199 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u text='%s')", (uint) event->text.timestamp, (uint) event->text.windowID, event->text.text);
203 SDL_EVENT_CASE(SDL_MOUSEMOTION)
204 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u state=%u x=%d y=%d xrel=%d yrel=%d)",
205 (uint) event->motion.timestamp, (uint) event->motion.windowID,
206 (uint) event->motion.which, (uint) event->motion.state,
207 (int) event->motion.x, (int) event->motion.y,
208 (int) event->motion.xrel, (int) event->motion.yrel);
211 #define PRINT_MBUTTON_EVENT(event) \
212 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u button=%u state=%s clicks=%u x=%d y=%d)", \
213 (uint) event->button.timestamp, (uint) event->button.windowID, \
214 (uint) event->button.which, (uint) event->button.button, \
215 event->button.state == SDL_PRESSED ? "pressed" : "released", \
216 (uint) event->button.clicks, (int) event->button.x, (int) event->button.y)
217 SDL_EVENT_CASE(SDL_MOUSEBUTTONDOWN) PRINT_MBUTTON_EVENT(event); break;
218 SDL_EVENT_CASE(SDL_MOUSEBUTTONUP) PRINT_MBUTTON_EVENT(event); break;
219 #undef PRINT_MBUTTON_EVENT
222 SDL_EVENT_CASE(SDL_MOUSEWHEEL)
223 SDL_snprintf(details, sizeof (details), " (timestamp=%u windowid=%u which=%u x=%d y=%d direction=%s)",
224 (uint) event->wheel.timestamp, (uint) event->wheel.windowID,
225 (uint) event->wheel.which, (int) event->wheel.x, (int) event->wheel.y,
226 event->wheel.direction == SDL_MOUSEWHEEL_NORMAL ? "normal" : "flipped");
229 SDL_EVENT_CASE(SDL_JOYAXISMOTION)
230 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)",
231 (uint) event->jaxis.timestamp, (int) event->jaxis.which,
232 (uint) event->jaxis.axis, (int) event->jaxis.value);
235 SDL_EVENT_CASE(SDL_JOYBALLMOTION)
236 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)",
237 (uint) event->jball.timestamp, (int) event->jball.which,
238 (uint) event->jball.ball, (int) event->jball.xrel, (int) event->jball.yrel);
241 SDL_EVENT_CASE(SDL_JOYHATMOTION)
242 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d hat=%u value=%u)",
243 (uint) event->jhat.timestamp, (int) event->jhat.which,
244 (uint) event->jhat.hat, (uint) event->jhat.value);
247 #define PRINT_JBUTTON_EVENT(event) \
248 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \
249 (uint) event->jbutton.timestamp, (int) event->jbutton.which, \
250 (uint) event->jbutton.button, event->jbutton.state == SDL_PRESSED ? "pressed" : "released")
251 SDL_EVENT_CASE(SDL_JOYBUTTONDOWN) PRINT_JBUTTON_EVENT(event); break;
252 SDL_EVENT_CASE(SDL_JOYBUTTONUP) PRINT_JBUTTON_EVENT(event); break;
253 #undef PRINT_JBUTTON_EVENT
255 #define PRINT_JOYDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->jdevice.timestamp, (int) event->jdevice.which)
256 SDL_EVENT_CASE(SDL_JOYDEVICEADDED) PRINT_JOYDEV_EVENT(event); break;
257 SDL_EVENT_CASE(SDL_JOYDEVICEREMOVED) PRINT_JOYDEV_EVENT(event); break;
258 #undef PRINT_JOYDEV_EVENT
260 SDL_EVENT_CASE(SDL_CONTROLLERAXISMOTION)
261 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d axis=%u value=%d)",
262 (uint) event->caxis.timestamp, (int) event->caxis.which,
263 (uint) event->caxis.axis, (int) event->caxis.value);
266 #define PRINT_CBUTTON_EVENT(event) \
267 SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d button=%u state=%s)", \
268 (uint) event->cbutton.timestamp, (int) event->cbutton.which, \
269 (uint) event->cbutton.button, event->cbutton.state == SDL_PRESSED ? "pressed" : "released")
270 SDL_EVENT_CASE(SDL_CONTROLLERBUTTONDOWN) PRINT_CBUTTON_EVENT(event); break;
271 SDL_EVENT_CASE(SDL_CONTROLLERBUTTONUP) PRINT_CBUTTON_EVENT(event); break;
272 #undef PRINT_CBUTTON_EVENT
274 #define PRINT_CONTROLLERDEV_EVENT(event) SDL_snprintf(details, sizeof (details), " (timestamp=%u which=%d)", (uint) event->cdevice.timestamp, (int) event->cdevice.which)
275 SDL_EVENT_CASE(SDL_CONTROLLERDEVICEADDED) PRINT_CONTROLLERDEV_EVENT(event); break;
276 SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMOVED) PRINT_CONTROLLERDEV_EVENT(event); break;
277 SDL_EVENT_CASE(SDL_CONTROLLERDEVICEREMAPPED) PRINT_CONTROLLERDEV_EVENT(event); break;
278 #undef PRINT_CONTROLLERDEV_EVENT
280 #define PRINT_FINGER_EVENT(event) \
281 SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" fingerid=%"SDL_PRIs64" x=%f y=%f dx=%f dy=%f pressure=%f)", \
282 (uint) event->tfinger.timestamp, event->tfinger.touchId, \
283 event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \
284 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure)
285 SDL_EVENT_CASE(SDL_FINGERDOWN) PRINT_FINGER_EVENT(event); break;
286 SDL_EVENT_CASE(SDL_FINGERUP) PRINT_FINGER_EVENT(event); break;
287 SDL_EVENT_CASE(SDL_FINGERMOTION) PRINT_FINGER_EVENT(event); break;
288 #undef PRINT_FINGER_EVENT
290 #define PRINT_DOLLAR_EVENT(event) \
291 SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" gestureid=%"SDL_PRIs64" numfingers=%u error=%f x=%f y=%f)", \
292 (uint) event->dgesture.timestamp, event->dgesture.touchId, \
293 event->dgesture.gestureId, (uint) event->dgesture.numFingers, \
294 event->dgesture.error, event->dgesture.x, event->dgesture.y);
295 SDL_EVENT_CASE(SDL_DOLLARGESTURE) PRINT_DOLLAR_EVENT(event); break;
296 SDL_EVENT_CASE(SDL_DOLLARRECORD) PRINT_DOLLAR_EVENT(event); break;
297 #undef PRINT_DOLLAR_EVENT
299 SDL_EVENT_CASE(SDL_MULTIGESTURE)
300 SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" dtheta=%f ddist=%f x=%f y=%f numfingers=%u)",
301 (uint) event->mgesture.timestamp, event->mgesture.touchId,
302 event->mgesture.dTheta, event->mgesture.dDist,
303 event->mgesture.x, event->mgesture.y, (uint) event->mgesture.numFingers);
306 #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)
307 SDL_EVENT_CASE(SDL_DROPFILE) PRINT_DROP_EVENT(event); break;
308 SDL_EVENT_CASE(SDL_DROPTEXT) PRINT_DROP_EVENT(event); break;
309 SDL_EVENT_CASE(SDL_DROPBEGIN) PRINT_DROP_EVENT(event); break;
310 SDL_EVENT_CASE(SDL_DROPCOMPLETE) PRINT_DROP_EVENT(event); break;
311 #undef PRINT_DROP_EVENT
313 #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");
314 SDL_EVENT_CASE(SDL_AUDIODEVICEADDED) PRINT_AUDIODEV_EVENT(event); break;
315 SDL_EVENT_CASE(SDL_AUDIODEVICEREMOVED) PRINT_AUDIODEV_EVENT(event); break;
316 #undef PRINT_AUDIODEV_EVENT
318 #undef SDL_EVENT_CASE
322 SDL_strlcpy(name, "UNKNOWN", sizeof (name));
323 SDL_snprintf(details, sizeof (details), " #%u! (Bug? FIXME?)", (uint) event->type);
329 SDL_Log("SDL EVENT: %s%s", name, details);
337 /* Public functions */
340 SDL_StopEventLoop(void)
342 const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
344 SDL_EventEntry *entry;
345 SDL_SysWMEntry *wmmsg;
347 if (SDL_EventQ.lock) {
348 SDL_LockMutex(SDL_EventQ.lock);
351 SDL_AtomicSet(&SDL_EventQ.active, 0);
353 if (report && SDL_atoi(report)) {
354 SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n",
355 SDL_EventQ.max_events_seen);
358 /* Clean out EventQ */
359 for (entry = SDL_EventQ.head; entry; ) {
360 SDL_EventEntry *next = entry->next;
364 for (entry = SDL_EventQ.free; entry; ) {
365 SDL_EventEntry *next = entry->next;
369 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
370 SDL_SysWMEntry *next = wmmsg->next;
374 for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
375 SDL_SysWMEntry *next = wmmsg->next;
380 SDL_AtomicSet(&SDL_EventQ.count, 0);
381 SDL_EventQ.max_events_seen = 0;
382 SDL_EventQ.head = NULL;
383 SDL_EventQ.tail = NULL;
384 SDL_EventQ.free = NULL;
385 SDL_EventQ.wmmsg_used = NULL;
386 SDL_EventQ.wmmsg_free = NULL;
388 /* Clear disabled event state */
389 for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
390 SDL_free(SDL_disabled_events[i]);
391 SDL_disabled_events[i] = NULL;
394 if (SDL_event_watchers_lock) {
395 SDL_DestroyMutex(SDL_event_watchers_lock);
396 SDL_event_watchers_lock = NULL;
398 if (SDL_event_watchers) {
399 SDL_free(SDL_event_watchers);
400 SDL_event_watchers = NULL;
401 SDL_event_watchers_count = 0;
403 SDL_zero(SDL_EventOK);
405 if (SDL_EventQ.lock) {
406 SDL_UnlockMutex(SDL_EventQ.lock);
407 SDL_DestroyMutex(SDL_EventQ.lock);
408 SDL_EventQ.lock = NULL;
412 /* This function (and associated calls) may be called more than once */
414 SDL_StartEventLoop(void)
416 /* We'll leave the event queue alone, since we might have gotten
417 some important events at launch (like SDL_DROPFILE)
419 FIXME: Does this introduce any other bugs with events at startup?
422 /* Create the lock and set ourselves active */
423 #if !SDL_THREADS_DISABLED
424 if (!SDL_EventQ.lock) {
425 SDL_EventQ.lock = SDL_CreateMutex();
426 if (SDL_EventQ.lock == NULL) {
431 if (!SDL_event_watchers_lock) {
432 SDL_event_watchers_lock = SDL_CreateMutex();
433 if (SDL_event_watchers_lock == NULL) {
437 #endif /* !SDL_THREADS_DISABLED */
439 /* Process most event types */
440 SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
441 SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
442 SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
443 #if 0 /* Leave these events enabled so apps can respond to items being dragged onto them at startup */
444 SDL_EventState(SDL_DROPFILE, SDL_DISABLE);
445 SDL_EventState(SDL_DROPTEXT, SDL_DISABLE);
448 SDL_AtomicSet(&SDL_EventQ.active, 1);
454 /* Add an event to the event queue -- called with the queue locked */
456 SDL_AddEvent(SDL_Event * event)
458 SDL_EventEntry *entry;
459 const int initial_count = SDL_AtomicGet(&SDL_EventQ.count);
462 if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
463 SDL_SetError("Event queue is full (%d events)", initial_count);
467 if (SDL_EventQ.free == NULL) {
468 entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
473 entry = SDL_EventQ.free;
474 SDL_EventQ.free = entry->next;
477 if (SDL_DoEventLogging) {
481 entry->event = *event;
482 if (event->type == SDL_SYSWMEVENT) {
483 entry->msg = *event->syswm.msg;
484 entry->event.syswm.msg = &entry->msg;
487 if (SDL_EventQ.tail) {
488 SDL_EventQ.tail->next = entry;
489 entry->prev = SDL_EventQ.tail;
490 SDL_EventQ.tail = entry;
493 SDL_assert(!SDL_EventQ.head);
494 SDL_EventQ.head = entry;
495 SDL_EventQ.tail = entry;
500 final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1;
501 if (final_count > SDL_EventQ.max_events_seen) {
502 SDL_EventQ.max_events_seen = final_count;
508 /* Remove an event from the queue -- called with the queue locked */
510 SDL_CutEvent(SDL_EventEntry *entry)
513 entry->prev->next = entry->next;
516 entry->next->prev = entry->prev;
519 if (entry == SDL_EventQ.head) {
520 SDL_assert(entry->prev == NULL);
521 SDL_EventQ.head = entry->next;
523 if (entry == SDL_EventQ.tail) {
524 SDL_assert(entry->next == NULL);
525 SDL_EventQ.tail = entry->prev;
528 entry->next = SDL_EventQ.free;
529 SDL_EventQ.free = entry;
530 SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0);
531 SDL_AtomicAdd(&SDL_EventQ.count, -1);
534 /* Lock the event queue, take a peep at it, and unlock it */
536 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
537 Uint32 minType, Uint32 maxType)
541 /* Don't look after we've quit */
542 if (!SDL_AtomicGet(&SDL_EventQ.active)) {
543 /* We get a few spurious events at shutdown, so don't warn then */
544 if (action != SDL_ADDEVENT) {
545 SDL_SetError("The event system has been shut down");
549 /* Lock the event queue */
551 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
552 if (action == SDL_ADDEVENT) {
553 for (i = 0; i < numevents; ++i) {
554 used += SDL_AddEvent(&events[i]);
557 SDL_EventEntry *entry, *next;
558 SDL_SysWMEntry *wmmsg, *wmmsg_next;
561 if (action == SDL_GETEVENT) {
562 /* Clean out any used wmmsg data
563 FIXME: Do we want to retain the data for some period of time?
565 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
566 wmmsg_next = wmmsg->next;
567 wmmsg->next = SDL_EventQ.wmmsg_free;
568 SDL_EventQ.wmmsg_free = wmmsg;
570 SDL_EventQ.wmmsg_used = NULL;
573 for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) {
575 type = entry->event.type;
576 if (minType <= type && type <= maxType) {
578 events[used] = entry->event;
579 if (entry->event.type == SDL_SYSWMEVENT) {
580 /* We need to copy the wmmsg somewhere safe.
581 For now we'll guarantee it's valid at least until
582 the next call to SDL_PeepEvents()
584 if (SDL_EventQ.wmmsg_free) {
585 wmmsg = SDL_EventQ.wmmsg_free;
586 SDL_EventQ.wmmsg_free = wmmsg->next;
588 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
590 wmmsg->msg = *entry->event.syswm.msg;
591 wmmsg->next = SDL_EventQ.wmmsg_used;
592 SDL_EventQ.wmmsg_used = wmmsg;
593 events[used].syswm.msg = &wmmsg->msg;
596 if (action == SDL_GETEVENT) {
604 if (SDL_EventQ.lock) {
605 SDL_UnlockMutex(SDL_EventQ.lock);
608 return SDL_SetError("Couldn't lock event queue");
614 SDL_HasEvent(Uint32 type)
616 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
620 SDL_HasEvents(Uint32 minType, Uint32 maxType)
622 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
626 SDL_FlushEvent(Uint32 type)
628 SDL_FlushEvents(type, type);
632 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
634 /* !!! FIXME: we need to manually SDL_free() the strings in TEXTINPUT and
635 drag'n'drop events if we're flushing them without passing them to the
636 app, but I don't know if this is the right place to do that. */
638 /* Don't look after we've quit */
639 if (!SDL_AtomicGet(&SDL_EventQ.active)) {
643 /* Make sure the events are current */
645 /* Actually, we can't do this since we might be flushing while processing
646 a resize event, and calling this might trigger further resize events.
651 /* Lock the event queue */
652 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
653 SDL_EventEntry *entry, *next;
655 for (entry = SDL_EventQ.head; entry; entry = next) {
657 type = entry->event.type;
658 if (minType <= type && type <= maxType) {
662 if (SDL_EventQ.lock) {
663 SDL_UnlockMutex(SDL_EventQ.lock);
668 /* Run the system dependent event loops */
672 SDL_VideoDevice *_this = SDL_GetVideoDevice();
674 /* Get events from the video subsystem */
676 _this->PumpEvents(_this);
678 #if !SDL_JOYSTICK_DISABLED
679 /* Check for joystick state change */
680 if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
681 SDL_JoystickUpdate();
685 #if !SDL_SENSOR_DISABLED
686 /* Check for sensor state change */
687 if (!SDL_disabled_events[SDL_SENSORUPDATE >> 8]) {
692 SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
695 /* Public functions */
698 SDL_PollEvent(SDL_Event * event)
700 return SDL_WaitEventTimeout(event, 0);
704 SDL_WaitEvent(SDL_Event * event)
706 return SDL_WaitEventTimeout(event, -1);
710 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
712 Uint32 expiration = 0;
715 expiration = SDL_GetTicks() + timeout;
719 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
724 /* Polling and no events, just return */
727 if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
728 /* Timeout expired and no events */
741 SDL_PushEvent(SDL_Event * event)
743 event->common.timestamp = SDL_GetTicks();
745 if (SDL_EventOK.callback || SDL_event_watchers_count > 0) {
746 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
747 if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) {
748 if (SDL_event_watchers_lock) {
749 SDL_UnlockMutex(SDL_event_watchers_lock);
754 if (SDL_event_watchers_count > 0) {
755 /* Make sure we only dispatch the current watcher list */
756 int i, event_watchers_count = SDL_event_watchers_count;
758 SDL_event_watchers_dispatching = SDL_TRUE;
759 for (i = 0; i < event_watchers_count; ++i) {
760 if (!SDL_event_watchers[i].removed) {
761 SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event);
764 SDL_event_watchers_dispatching = SDL_FALSE;
766 if (SDL_event_watchers_removed) {
767 for (i = SDL_event_watchers_count; i--; ) {
768 if (SDL_event_watchers[i].removed) {
769 --SDL_event_watchers_count;
770 if (i < SDL_event_watchers_count) {
771 SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
775 SDL_event_watchers_removed = SDL_FALSE;
779 if (SDL_event_watchers_lock) {
780 SDL_UnlockMutex(SDL_event_watchers_lock);
785 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
789 SDL_GestureProcessEvent(event);
795 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
797 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
798 /* Set filter and discard pending events */
799 SDL_EventOK.callback = filter;
800 SDL_EventOK.userdata = userdata;
801 SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
803 if (SDL_event_watchers_lock) {
804 SDL_UnlockMutex(SDL_event_watchers_lock);
810 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
812 SDL_EventWatcher event_ok;
814 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
815 event_ok = SDL_EventOK;
817 if (SDL_event_watchers_lock) {
818 SDL_UnlockMutex(SDL_event_watchers_lock);
825 *filter = event_ok.callback;
828 *userdata = event_ok.userdata;
830 return event_ok.callback ? SDL_TRUE : SDL_FALSE;
834 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
836 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
837 SDL_EventWatcher *event_watchers;
839 event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
840 if (event_watchers) {
841 SDL_EventWatcher *watcher;
843 SDL_event_watchers = event_watchers;
844 watcher = &SDL_event_watchers[SDL_event_watchers_count];
845 watcher->callback = filter;
846 watcher->userdata = userdata;
847 watcher->removed = SDL_FALSE;
848 ++SDL_event_watchers_count;
851 if (SDL_event_watchers_lock) {
852 SDL_UnlockMutex(SDL_event_watchers_lock);
858 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
860 if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
863 for (i = 0; i < SDL_event_watchers_count; ++i) {
864 if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) {
865 if (SDL_event_watchers_dispatching) {
866 SDL_event_watchers[i].removed = SDL_TRUE;
867 SDL_event_watchers_removed = SDL_TRUE;
869 --SDL_event_watchers_count;
870 if (i < SDL_event_watchers_count) {
871 SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
878 if (SDL_event_watchers_lock) {
879 SDL_UnlockMutex(SDL_event_watchers_lock);
885 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
887 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
888 SDL_EventEntry *entry, *next;
889 for (entry = SDL_EventQ.head; entry; entry = next) {
891 if (!filter(userdata, &entry->event)) {
895 if (SDL_EventQ.lock) {
896 SDL_UnlockMutex(SDL_EventQ.lock);
902 SDL_EventState(Uint32 type, int state)
904 const SDL_bool isdnd = ((state == SDL_DISABLE) || (state == SDL_ENABLE)) &&
905 ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT));
907 Uint8 hi = ((type >> 8) & 0xff);
908 Uint8 lo = (type & 0xff);
910 if (SDL_disabled_events[hi] &&
911 (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
912 current_state = SDL_DISABLE;
914 current_state = SDL_ENABLE;
917 if (state != current_state)
921 /* Disable this event type and discard pending events */
922 if (!SDL_disabled_events[hi]) {
923 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
924 if (!SDL_disabled_events[hi]) {
925 /* Out of memory, nothing we can do... */
929 SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
930 SDL_FlushEvent(type);
933 SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
936 /* Querying state... */
941 /* turn off drag'n'drop support if we've disabled the events.
942 This might change some UI details at the OS level. */
944 SDL_ToggleDragAndDropSupport();
947 return current_state;
951 SDL_RegisterEvents(int numevents)
955 if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
956 event_base = SDL_userevents;
957 SDL_userevents += numevents;
959 event_base = (Uint32)-1;
965 SDL_SendAppEvent(SDL_EventType eventType)
970 if (SDL_GetEventState(eventType) == SDL_ENABLE) {
972 event.type = eventType;
973 posted = (SDL_PushEvent(&event) > 0);
979 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
984 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
986 SDL_memset(&event, 0, sizeof(event));
987 event.type = SDL_SYSWMEVENT;
988 event.syswm.msg = message;
989 posted = (SDL_PushEvent(&event) > 0);
991 /* Update internal event state */
996 SDL_SendKeymapChangedEvent(void)
998 return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
1002 SDL_EventsInit(void)
1004 SDL_AddHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1005 if (SDL_StartEventLoop() < 0) {
1006 SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1016 SDL_EventsQuit(void)
1019 SDL_StopEventLoop();
1020 SDL_DelHintCallback(SDL_HINT_EVENT_LOGGING, SDL_EventLoggingChanged, NULL);
1023 /* vi: set ts=4 sw=4 expandtab: */