2 Simple DirectMedia Layer
3 Copyright (C) 1997-2012 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_config.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 /* Public data -- the event filter */
37 SDL_EventFilter SDL_EventOK = NULL;
38 void *SDL_EventOKParam;
40 typedef struct SDL_EventWatcher {
41 SDL_EventFilter callback;
43 struct SDL_EventWatcher *next;
46 static SDL_EventWatcher *SDL_event_watchers = NULL;
50 } SDL_DisabledEventBlock;
52 static SDL_DisabledEventBlock *SDL_disabled_events[256];
53 static Uint32 SDL_userevents = SDL_USEREVENT;
55 /* Private data -- event queue */
63 SDL_Event event[MAXEVENTS];
65 struct SDL_SysWMmsg wmmsg[MAXEVENTS];
66 } SDL_EventQ = { NULL, 1 };
69 static __inline__ SDL_bool
70 SDL_ShouldPollJoystick()
72 #if !SDL_JOYSTICK_DISABLED
73 if (SDL_numjoysticks &&
74 (!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] ||
75 SDL_JoystickEventState(SDL_QUERY))) {
82 /* Public functions */
85 SDL_StopEventLoop(void)
89 SDL_EventQ.active = 0;
91 if (SDL_EventQ.lock) {
92 SDL_DestroyMutex(SDL_EventQ.lock);
93 SDL_EventQ.lock = NULL;
96 /* Clean out EventQ */
99 SDL_EventQ.wmmsg_next = 0;
101 /* Clear disabled event state */
102 for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
103 if (SDL_disabled_events[i]) {
104 SDL_free(SDL_disabled_events[i]);
105 SDL_disabled_events[i] = NULL;
109 while (SDL_event_watchers) {
110 SDL_EventWatcher *tmp = SDL_event_watchers;
111 SDL_event_watchers = tmp->next;
116 /* This function (and associated calls) may be called more than once */
118 SDL_StartEventLoop(void)
120 /* We'll leave the event queue alone, since we might have gotten
121 some important events at launch (like SDL_DROPFILE)
123 FIXME: Does this introduce any other bugs with events at startup?
126 /* No filter to start with, process most event types */
128 SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
130 /* If text input shows UI onscreen we want to start with it disabled */
131 if (SDL_HasScreenKeyboardSupport()) {
132 SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE);
133 SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
136 /* Create the lock and set ourselves active */
137 #if !SDL_THREADS_DISABLED
138 if (!SDL_EventQ.lock) {
139 SDL_EventQ.lock = SDL_CreateMutex();
141 if (SDL_EventQ.lock == NULL) {
144 #endif /* !SDL_THREADS_DISABLED */
145 SDL_EventQ.active = 1;
151 /* Add an event to the event queue -- called with the queue locked */
153 SDL_AddEvent(SDL_Event * event)
157 tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
158 if (tail == SDL_EventQ.head) {
159 /* Overflow, drop event */
162 SDL_EventQ.event[SDL_EventQ.tail] = *event;
163 if (event->type == SDL_SYSWMEVENT) {
164 /* Note that it's possible to lose an event */
165 int next = SDL_EventQ.wmmsg_next;
166 SDL_EventQ.wmmsg[next] = *event->syswm.msg;
167 SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
168 &SDL_EventQ.wmmsg[next];
169 SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
171 SDL_EventQ.tail = tail;
177 /* Cut an event, and return the next valid spot, or the tail */
178 /* -- called with the queue locked */
180 SDL_CutEvent(int spot)
182 if (spot == SDL_EventQ.head) {
183 SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
184 return (SDL_EventQ.head);
185 } else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
186 SDL_EventQ.tail = spot;
187 return (SDL_EventQ.tail);
189 /* We cut the middle -- shift everything over */
193 /* This can probably be optimized with SDL_memcpy() -- careful! */
194 if (--SDL_EventQ.tail < 0) {
195 SDL_EventQ.tail = MAXEVENTS - 1;
197 for (here = spot; here != SDL_EventQ.tail; here = next) {
198 next = (here + 1) % MAXEVENTS;
199 SDL_EventQ.event[here] = SDL_EventQ.event[next];
206 /* Lock the event queue, take a peep at it, and unlock it */
208 SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
209 Uint32 minType, Uint32 maxType)
213 /* Don't look after we've quit */
214 if (!SDL_EventQ.active) {
217 /* Lock the event queue */
219 if (!SDL_EventQ.lock || SDL_mutexP(SDL_EventQ.lock) == 0) {
220 if (action == SDL_ADDEVENT) {
221 for (i = 0; i < numevents; ++i) {
222 used += SDL_AddEvent(&events[i]);
228 /* If 'events' is NULL, just see if they exist */
229 if (events == NULL) {
230 action = SDL_PEEKEVENT;
234 spot = SDL_EventQ.head;
235 while ((used < numevents) && (spot != SDL_EventQ.tail)) {
236 Uint32 type = SDL_EventQ.event[spot].type;
237 if (minType <= type && type <= maxType) {
238 events[used++] = SDL_EventQ.event[spot];
239 if (action == SDL_GETEVENT) {
240 spot = SDL_CutEvent(spot);
242 spot = (spot + 1) % MAXEVENTS;
245 spot = (spot + 1) % MAXEVENTS;
249 SDL_mutexV(SDL_EventQ.lock);
251 SDL_SetError("Couldn't lock event queue");
258 SDL_HasEvent(Uint32 type)
260 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0);
264 SDL_HasEvents(Uint32 minType, Uint32 maxType)
266 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0);
270 SDL_FlushEvent(Uint32 type)
272 SDL_FlushEvents(type, type);
276 SDL_FlushEvents(Uint32 minType, Uint32 maxType)
278 /* Don't look after we've quit */
279 if (!SDL_EventQ.active) {
283 /* Make sure the events are current */
285 /* Actually, we can't do this since we might be flushing while processing
286 a resize event, and calling this might trigger further resize events.
291 /* Lock the event queue */
292 if (SDL_mutexP(SDL_EventQ.lock) == 0) {
293 int spot = SDL_EventQ.head;
294 while (spot != SDL_EventQ.tail) {
295 Uint32 type = SDL_EventQ.event[spot].type;
296 if (minType <= type && type <= maxType) {
297 spot = SDL_CutEvent(spot);
299 spot = (spot + 1) % MAXEVENTS;
302 SDL_mutexV(SDL_EventQ.lock);
306 /* Run the system dependent event loops */
310 SDL_VideoDevice *_this = SDL_GetVideoDevice();
312 /* Get events from the video subsystem */
314 _this->PumpEvents(_this);
316 #if !SDL_JOYSTICK_DISABLED
317 /* Check for joystick state change */
318 if (SDL_ShouldPollJoystick()) {
319 SDL_JoystickUpdate();
324 /* Public functions */
327 SDL_PollEvent(SDL_Event * event)
329 return SDL_WaitEventTimeout(event, 0);
333 SDL_WaitEvent(SDL_Event * event)
335 return SDL_WaitEventTimeout(event, -1);
339 SDL_WaitEventTimeout(SDL_Event * event, int timeout)
341 Uint32 expiration = 0;
344 expiration = SDL_GetTicks() + timeout;
348 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
355 /* Polling and no events, just return */
358 if (timeout > 0 && ((int) (SDL_GetTicks() - expiration) >= 0)) {
359 /* Timeout expired and no events */
369 SDL_PushEvent(SDL_Event * event)
371 SDL_EventWatcher *curr;
372 event->window.timestamp = SDL_GetTicks();
373 if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
377 for (curr = SDL_event_watchers; curr; curr = curr->next) {
378 curr->callback(curr->userdata, event);
381 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
385 SDL_GestureProcessEvent(event);
391 SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
395 /* Set filter and discard pending events */
396 SDL_EventOK = filter;
397 SDL_EventOKParam = userdata;
398 while (SDL_PollEvent(&bitbucket) > 0);
402 SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
405 *filter = SDL_EventOK;
408 *userdata = SDL_EventOKParam;
410 return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
413 /* FIXME: This is not thread-safe yet */
415 SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
417 SDL_EventWatcher *watcher;
419 watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
424 watcher->callback = filter;
425 watcher->userdata = userdata;
426 watcher->next = SDL_event_watchers;
427 SDL_event_watchers = watcher;
430 /* FIXME: This is not thread-safe yet */
432 SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
434 SDL_EventWatcher *prev = NULL;
435 SDL_EventWatcher *curr;
437 for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
438 if (curr->callback == filter && curr->userdata == userdata) {
440 prev->next = curr->next;
442 SDL_event_watchers = curr->next;
451 SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
453 if (SDL_mutexP(SDL_EventQ.lock) == 0) {
456 spot = SDL_EventQ.head;
457 while (spot != SDL_EventQ.tail) {
458 if (filter(userdata, &SDL_EventQ.event[spot])) {
459 spot = (spot + 1) % MAXEVENTS;
461 spot = SDL_CutEvent(spot);
465 SDL_mutexV(SDL_EventQ.lock);
469 SDL_EventState(Uint32 type, int state)
472 Uint8 hi = ((type >> 8) & 0xff);
473 Uint8 lo = (type & 0xff);
475 if (SDL_disabled_events[hi] &&
476 (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) {
477 current_state = SDL_DISABLE;
479 current_state = SDL_ENABLE;
482 if (state != current_state)
486 /* Disable this event type and discard pending events */
487 if (!SDL_disabled_events[hi]) {
488 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock));
489 if (!SDL_disabled_events[hi]) {
490 /* Out of memory, nothing we can do... */
494 SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31));
495 SDL_FlushEvent(type);
498 SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31));
501 /* Querying state... */
506 return current_state;
510 SDL_RegisterEvents(int numevents)
514 if (SDL_userevents+numevents <= SDL_LASTEVENT) {
515 event_base = SDL_userevents;
516 SDL_userevents += numevents;
518 event_base = (Uint32)-1;
523 /* This is a generic event handler.
526 SDL_SendSysWMEvent(SDL_SysWMmsg * message)
531 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
533 SDL_memset(&event, 0, sizeof(event));
534 event.type = SDL_SYSWMEVENT;
535 event.syswm.msg = message;
536 posted = (SDL_PushEvent(&event) > 0);
538 /* Update internal event state */
542 /* vi: set ts=4 sw=4 expandtab: */