2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 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_syswm.h"
28 #include "SDL_thread.h"
29 #include "SDL_events_c.h"
30 #include "../timer/SDL_timer_c.h"
31 #if !SDL_JOYSTICK_DISABLED
32 #include "../joystick/SDL_joystick_c.h"
34 #include "../video/SDL_sysvideo.h"
36 /* An arbitrary limit so we don't have unbounded growth */
37 #define SDL_MAX_QUEUED_EVENTS 65535
39 /* Public data -- the event filter */
40 SDL_EventFilter SDL_EventOK = NULL;
41 void *SDL_EventOKParam;
43 typedef struct SDL_EventWatcher {
44 SDL_EventFilter callback;
46 struct SDL_EventWatcher *next;
49 static SDL_EventWatcher *SDL_event_watchers = NULL;
53 } SDL_DisabledEventBlock;
55 static SDL_DisabledEventBlock *SDL_disabled_events[256];
56 static Uint32 SDL_userevents = SDL_USEREVENT;
58 /* Private data -- event queue */
59 typedef struct _SDL_EventEntry
63 struct _SDL_EventEntry *prev;
64 struct _SDL_EventEntry *next;
67 typedef struct _SDL_SysWMEntry
70 struct _SDL_SysWMEntry *next;
76 volatile SDL_bool active;
78 volatile int max_events_seen;
82 SDL_SysWMEntry *wmmsg_used;
83 SDL_SysWMEntry *wmmsg_free;
84 } SDL_EventQ = { NULL, SDL_TRUE, 0, 0, NULL, NULL, NULL, NULL, NULL };
87 /* Public functions */
90 SDL_StopEventLoop(void)
92 const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS");
94 SDL_EventEntry *entry;
95 SDL_SysWMEntry *wmmsg;
97 if (SDL_EventQ.lock) {
98 SDL_LockMutex(SDL_EventQ.lock);
101 SDL_EventQ.active = SDL_FALSE;
103 if (report && SDL_atoi(report)) {
104 SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n",
105 SDL_EventQ.max_events_seen);
108 /* Clean out EventQ */
109 for (entry = SDL_EventQ.head; entry; ) {
110 SDL_EventEntry *next = entry->next;
114 for (entry = SDL_EventQ.free; entry; ) {
115 SDL_EventEntry *next = entry->next;
119 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
120 SDL_SysWMEntry *next = wmmsg->next;
124 for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
125 SDL_SysWMEntry *next = wmmsg->next;
130 SDL_EventQ.count = 0;
131 SDL_EventQ.max_events_seen = 0;
132 SDL_EventQ.head = NULL;
133 SDL_EventQ.tail = NULL;
134 SDL_EventQ.free = NULL;
135 SDL_EventQ.wmmsg_used = NULL;
136 SDL_EventQ.wmmsg_free = NULL;
138 /* Clear disabled event state */
139 for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
140 SDL_free(SDL_disabled_events[i]);
141 SDL_disabled_events[i] = NULL;
144 while (SDL_event_watchers) {
145 SDL_EventWatcher *tmp = SDL_event_watchers;
146 SDL_event_watchers = tmp->next;
151 if (SDL_EventQ.lock) {
152 SDL_UnlockMutex(SDL_EventQ.lock);
153 SDL_DestroyMutex(SDL_EventQ.lock);
154 SDL_EventQ.lock = NULL;
158 /* This function (and associated calls) may be called more than once */
160 SDL_StartEventLoop(void)
162 /* We'll leave the event queue alone, since we might have gotten
163 some important events at launch (like SDL_DROPFILE)
165 FIXME: Does this introduce any other bugs with events at startup?
168 /* Create the lock and set ourselves active */
169 #if !SDL_THREADS_DISABLED
170 if (!SDL_EventQ.lock) {
171 SDL_EventQ.lock = SDL_CreateMutex();
173 if (SDL_EventQ.lock == NULL) {
176 #endif /* !SDL_THREADS_DISABLED */
178 /* Process most event types */
179 SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
180 SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
181 SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
183 SDL_EventQ.active = SDL_TRUE;
189 /* Add an event to the event queue -- called with the queue locked */
191 SDL_AddEvent(SDL_Event * event)
193 SDL_EventEntry *entry;
195 if (SDL_EventQ.count >= SDL_MAX_QUEUED_EVENTS) {
196 SDL_SetError("Event queue is full (%d events)", SDL_EventQ.count);
200 if (SDL_EventQ.free == NULL) {
201 entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
206 entry = SDL_EventQ.free;
207 SDL_EventQ.free = entry->next;
210 entry->event = *event;
211 if (event->type == SDL_SYSWMEVENT) {
212 entry->msg = *event->syswm.msg;
213 entry->event.syswm.msg = &entry->msg;
216 if (SDL_EventQ.tail) {
217 SDL_EventQ.tail->next = entry;
218 entry->prev = SDL_EventQ.tail;
219 SDL_EventQ.tail = entry;
222 SDL_assert(!SDL_EventQ.head);
223 SDL_EventQ.head = entry;
224 SDL_EventQ.tail = entry;
230 if (SDL_EventQ.count > SDL_EventQ.max_events_seen) {
231 SDL_EventQ.max_events_seen = SDL_EventQ.count;
237 /* Remove an event from the queue -- called with the queue locked */
239 SDL_CutEvent(SDL_EventEntry *entry)
242 entry->prev->next = entry->next;
245 entry->next->prev = entry->prev;
248 if (entry == SDL_EventQ.head) {
249 SDL_assert(entry->prev == NULL);
250 SDL_EventQ.head = entry->next;
252 if (entry == SDL_EventQ.tail) {
253 SDL_assert(entry->next == NULL);
254 SDL_EventQ.tail = entry->prev;
257 entry->next = SDL_EventQ.free;
258 SDL_EventQ.free = entry;
259 SDL_assert(SDL_EventQ.count > 0);
263 /* Lock the event queue, take a peep at it, and unlock it */
265 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
266 Uint32 minType, Uint32 maxType)
270 /* Don't look after we've quit */
271 if (!SDL_EventQ.active) {
272 /* We get a few spurious events at shutdown, so don't warn then */
273 if (action != SDL_ADDEVENT) {
274 SDL_SetError("The event system has been shut down");
278 /* Lock the event queue */
280 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
281 if (action == SDL_ADDEVENT) {
282 for (i = 0; i < numevents; ++i) {
283 used += SDL_AddEvent(&events[i]);
286 SDL_EventEntry *entry, *next;
287 SDL_SysWMEntry *wmmsg, *wmmsg_next;
291 /* If 'events' is NULL, just see if they exist */
292 if (events == NULL) {
293 action = SDL_PEEKEVENT;
298 /* Clean out any used wmmsg data
299 FIXME: Do we want to retain the data for some period of time?
301 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
302 wmmsg_next = wmmsg->next;
303 wmmsg->next = SDL_EventQ.wmmsg_free;
304 SDL_EventQ.wmmsg_free = wmmsg;
306 SDL_EventQ.wmmsg_used = NULL;
308 for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) {
310 type = entry->event.type;
311 if (minType <= type && type <= maxType) {
312 events[used] = entry->event;
313 if (entry->event.type == SDL_SYSWMEVENT) {
314 /* We need to copy the wmmsg somewhere safe.
315 For now we'll guarantee it's valid at least until
316 the next call to SDL_PeepEvents()
318 if (SDL_EventQ.wmmsg_free) {
319 wmmsg = SDL_EventQ.wmmsg_free;
320 SDL_EventQ.wmmsg_free = wmmsg->next;
322 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
324 wmmsg->msg = *entry->event.syswm.msg;
325 wmmsg->next = SDL_EventQ.wmmsg_used;
326 SDL_EventQ.wmmsg_used = wmmsg;
327 events[used].syswm.msg = &wmmsg->msg;
331 if (action == SDL_GETEVENT) {
337 SDL_UnlockMutex(SDL_EventQ.lock);
339 return SDL_SetError("Couldn't lock event queue");
345 SDL_HasEvent(Uint32 type)
347 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
351 SDL_HasEvents(Uint32 minType, Uint32 maxType)
353 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
357 SDL_FlushEvent(Uint32 type)
359 SDL_FlushEvents(type, type);
363 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
365 /* Don't look after we've quit */
366 if (!SDL_EventQ.active) {
370 /* Make sure the events are current */
372 /* Actually, we can't do this since we might be flushing while processing
373 a resize event, and calling this might trigger further resize events.
378 /* Lock the event queue */
379 if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
380 SDL_EventEntry *entry, *next;
382 for (entry = SDL_EventQ.head; entry; entry = next) {
384 type = entry->event.type;
385 if (minType <= type && type <= maxType) {
389 SDL_UnlockMutex(SDL_EventQ.lock);
393 /* Run the system dependent event loops */
397 SDL_VideoDevice *_this = SDL_GetVideoDevice();
398 /* Get events from the video subsystem */
400 _this->PumpEvents(_this);
402 #if !SDL_JOYSTICK_DISABLED
403 /* Check for joystick state change */
404 if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) {
405 SDL_JoystickUpdate();
408 SDL_SendPendingQuit(); /* in case we had a signal handler fire, etc. */
411 /* Public functions */
414 SDL_PollEvent(SDL_Event * event)
416 return SDL_WaitEventTimeout(event, 0);
420 SDL_WaitEvent(SDL_Event * event)
422 return SDL_WaitEventTimeout(event, -1);
426 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
428 Uint32 expiration = 0;
431 expiration = SDL_GetTicks() + timeout;
434 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
441 /* Polling and no events, just return */
444 if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) {
445 /* Timeout expired and no events */
455 SDL_PushEvent(SDL_Event * event)
457 SDL_EventWatcher *curr;
459 event->common.timestamp = SDL_GetTicks();
461 if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
465 for (curr = SDL_event_watchers; curr; curr = curr->next) {
466 curr->callback(curr->userdata, event);
469 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
473 SDL_VideoDevice *_this = SDL_GetVideoDevice();
474 SDL_GestureProcessEvent(event);
480 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
482 /* Set filter and discard pending events */
484 SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
485 SDL_EventOKParam = userdata;
486 SDL_EventOK = filter;
490 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
493 *filter = SDL_EventOK;
496 *userdata = SDL_EventOKParam;
498 return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
501 /* FIXME: This is not thread-safe yet */
503 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
505 SDL_EventWatcher *watcher, *tail;
507 watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
513 /* create the watcher */
514 watcher->callback = filter;
515 watcher->userdata = userdata;
516 watcher->next = NULL;
518 /* add the watcher to the end of the list */
519 if (SDL_event_watchers) {
520 for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
523 tail->next = watcher;
525 SDL_event_watchers = watcher;
529 /* FIXME: This is not thread-safe yet */
531 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
533 SDL_EventWatcher *prev = NULL;
534 SDL_EventWatcher *curr;
536 for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
537 if (curr->callback == filter && curr->userdata == userdata) {
539 prev->next = curr->next;
541 SDL_event_watchers = curr->next;
550 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
552 if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
553 SDL_EventEntry *entry, *next;
554 for (entry = SDL_EventQ.head; entry; entry = next) {
556 if (!filter(userdata, &entry->event)) {
560 SDL_UnlockMutex(SDL_EventQ.lock);
565 SDL_EventState(Uint32 type, int state)
568 Uint8 hi = ((type >> 8) & 0xff);
569 Uint8 lo = (type & 0xff);
571 if (SDL_disabled_events[hi] &&
572 (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
573 current_state = SDL_DISABLE;
575 current_state = SDL_ENABLE;
578 if (state != current_state)
582 /* Disable this event type and discard pending events */
583 if (!SDL_disabled_events[hi]) {
584 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
585 if (!SDL_disabled_events[hi]) {
586 /* Out of memory, nothing we can do... */
590 SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
591 SDL_FlushEvent(type);
594 SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
597 /* Querying state... */
602 return current_state;
606 SDL_RegisterEvents(int numevents)
610 if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) {
611 event_base = SDL_userevents;
612 SDL_userevents += numevents;
614 event_base = (Uint32)-1;
620 SDL_SendAppEvent(SDL_EventType eventType)
625 if (SDL_GetEventState(eventType) == SDL_ENABLE) {
627 event.type = eventType;
628 posted = (SDL_PushEvent(&event) > 0);
634 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
639 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
641 SDL_memset(&event, 0, sizeof(event));
642 event.type = SDL_SYSWMEVENT;
643 event.syswm.msg = message;
644 posted = (SDL_PushEvent(&event) > 0);
646 /* Update internal event state */
651 SDL_SendKeymapChangedEvent(void)
653 return SDL_SendAppEvent(SDL_KEYMAPCHANGED);
656 /* vi: set ts=4 sw=4 expandtab: */