SDL_events.c (16751B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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_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" 33#endif 34#include "../video/SDL_sysvideo.h" 35 36/* An arbitrary limit so we don't have unbounded growth */ 37#define SDL_MAX_QUEUED_EVENTS 65535 38 39/* Public data -- the event filter */ 40SDL_EventFilter SDL_EventOK = NULL; 41void *SDL_EventOKParam; 42 43typedef struct SDL_EventWatcher { 44 SDL_EventFilter callback; 45 void *userdata; 46 struct SDL_EventWatcher *next; 47} SDL_EventWatcher; 48 49static SDL_EventWatcher *SDL_event_watchers = NULL; 50 51typedef struct { 52 Uint32 bits[8]; 53} SDL_DisabledEventBlock; 54 55static SDL_DisabledEventBlock *SDL_disabled_events[256]; 56static Uint32 SDL_userevents = SDL_USEREVENT; 57 58/* Private data -- event queue */ 59typedef struct _SDL_EventEntry 60{ 61 SDL_Event event; 62 SDL_SysWMmsg msg; 63 struct _SDL_EventEntry *prev; 64 struct _SDL_EventEntry *next; 65} SDL_EventEntry; 66 67typedef struct _SDL_SysWMEntry 68{ 69 SDL_SysWMmsg msg; 70 struct _SDL_SysWMEntry *next; 71} SDL_SysWMEntry; 72 73static struct 74{ 75 SDL_mutex *lock; 76 volatile SDL_bool active; 77 volatile int count; 78 SDL_EventEntry *head; 79 SDL_EventEntry *tail; 80 SDL_EventEntry *free; 81 SDL_SysWMEntry *wmmsg_used; 82 SDL_SysWMEntry *wmmsg_free; 83} SDL_EventQ = { NULL, SDL_TRUE }; 84 85 86/* Public functions */ 87 88void 89SDL_StopEventLoop(void) 90{ 91 int i; 92 SDL_EventEntry *entry; 93 SDL_SysWMEntry *wmmsg; 94 95 if (SDL_EventQ.lock) { 96 SDL_LockMutex(SDL_EventQ.lock); 97 } 98 99 SDL_EventQ.active = SDL_FALSE; 100 101 /* Clean out EventQ */ 102 for (entry = SDL_EventQ.head; entry; ) { 103 SDL_EventEntry *next = entry->next; 104 SDL_free(entry); 105 entry = next; 106 } 107 for (entry = SDL_EventQ.free; entry; ) { 108 SDL_EventEntry *next = entry->next; 109 SDL_free(entry); 110 entry = next; 111 } 112 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) { 113 SDL_SysWMEntry *next = wmmsg->next; 114 SDL_free(wmmsg); 115 wmmsg = next; 116 } 117 for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) { 118 SDL_SysWMEntry *next = wmmsg->next; 119 SDL_free(wmmsg); 120 wmmsg = next; 121 } 122 SDL_EventQ.count = 0; 123 SDL_EventQ.head = NULL; 124 SDL_EventQ.tail = NULL; 125 SDL_EventQ.free = NULL; 126 SDL_EventQ.wmmsg_used = NULL; 127 SDL_EventQ.wmmsg_free = NULL; 128 129 /* Clear disabled event state */ 130 for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) { 131 SDL_free(SDL_disabled_events[i]); 132 SDL_disabled_events[i] = NULL; 133 } 134 135 while (SDL_event_watchers) { 136 SDL_EventWatcher *tmp = SDL_event_watchers; 137 SDL_event_watchers = tmp->next; 138 SDL_free(tmp); 139 } 140 SDL_EventOK = NULL; 141 142 if (SDL_EventQ.lock) { 143 SDL_UnlockMutex(SDL_EventQ.lock); 144 SDL_DestroyMutex(SDL_EventQ.lock); 145 SDL_EventQ.lock = NULL; 146 } 147} 148 149/* This function (and associated calls) may be called more than once */ 150int 151SDL_StartEventLoop(void) 152{ 153 /* We'll leave the event queue alone, since we might have gotten 154 some important events at launch (like SDL_DROPFILE) 155 156 FIXME: Does this introduce any other bugs with events at startup? 157 */ 158 159 /* Create the lock and set ourselves active */ 160#if !SDL_THREADS_DISABLED 161 if (!SDL_EventQ.lock) { 162 SDL_EventQ.lock = SDL_CreateMutex(); 163 } 164 if (SDL_EventQ.lock == NULL) { 165 return (-1); 166 } 167#endif /* !SDL_THREADS_DISABLED */ 168 169 /* Process most event types */ 170 SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); 171 SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); 172 SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE); 173 174 SDL_EventQ.active = SDL_TRUE; 175 176 return (0); 177} 178 179 180/* Add an event to the event queue -- called with the queue locked */ 181static int 182SDL_AddEvent(SDL_Event * event) 183{ 184 SDL_EventEntry *entry; 185 186 if (SDL_EventQ.count >= SDL_MAX_QUEUED_EVENTS) { 187 SDL_SetError("Event queue is full (%d events)", SDL_EventQ.count); 188 return 0; 189 } 190 191 if (SDL_EventQ.free == NULL) { 192 entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry)); 193 if (!entry) { 194 return 0; 195 } 196 } else { 197 entry = SDL_EventQ.free; 198 SDL_EventQ.free = entry->next; 199 } 200 201 entry->event = *event; 202 if (event->type == SDL_SYSWMEVENT) { 203 entry->msg = *event->syswm.msg; 204 entry->event.syswm.msg = &entry->msg; 205 } 206 207 if (SDL_EventQ.tail) { 208 SDL_EventQ.tail->next = entry; 209 entry->prev = SDL_EventQ.tail; 210 SDL_EventQ.tail = entry; 211 entry->next = NULL; 212 } else { 213 SDL_assert(!SDL_EventQ.head); 214 SDL_EventQ.head = entry; 215 SDL_EventQ.tail = entry; 216 entry->prev = NULL; 217 entry->next = NULL; 218 } 219 ++SDL_EventQ.count; 220 221 return 1; 222} 223 224/* Remove an event from the queue -- called with the queue locked */ 225static void 226SDL_CutEvent(SDL_EventEntry *entry) 227{ 228 if (entry->prev) { 229 entry->prev->next = entry->next; 230 } 231 if (entry->next) { 232 entry->next->prev = entry->prev; 233 } 234 235 if (entry == SDL_EventQ.head) { 236 SDL_assert(entry->prev == NULL); 237 SDL_EventQ.head = entry->next; 238 } 239 if (entry == SDL_EventQ.tail) { 240 SDL_assert(entry->next == NULL); 241 SDL_EventQ.tail = entry->prev; 242 } 243 244 entry->next = SDL_EventQ.free; 245 SDL_EventQ.free = entry; 246 SDL_assert(SDL_EventQ.count > 0); 247 --SDL_EventQ.count; 248} 249 250/* Lock the event queue, take a peep at it, and unlock it */ 251int 252SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action, 253 Uint32 minType, Uint32 maxType) 254{ 255 int i, used; 256 257 /* Don't look after we've quit */ 258 if (!SDL_EventQ.active) { 259 /* We get a few spurious events at shutdown, so don't warn then */ 260 if (action != SDL_ADDEVENT) { 261 SDL_SetError("The event system has been shut down"); 262 } 263 return (-1); 264 } 265 /* Lock the event queue */ 266 used = 0; 267 if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) { 268 if (action == SDL_ADDEVENT) { 269 for (i = 0; i < numevents; ++i) { 270 used += SDL_AddEvent(&events[i]); 271 } 272 } else { 273 SDL_EventEntry *entry, *next; 274 SDL_SysWMEntry *wmmsg, *wmmsg_next; 275 SDL_Event tmpevent; 276 Uint32 type; 277 278 /* If 'events' is NULL, just see if they exist */ 279 if (events == NULL) { 280 action = SDL_PEEKEVENT; 281 numevents = 1; 282 events = &tmpevent; 283 } 284 285 /* Clean out any used wmmsg data 286 FIXME: Do we want to retain the data for some period of time? 287 */ 288 for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) { 289 wmmsg_next = wmmsg->next; 290 wmmsg->next = SDL_EventQ.wmmsg_free; 291 SDL_EventQ.wmmsg_free = wmmsg; 292 } 293 SDL_EventQ.wmmsg_used = NULL; 294 295 for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) { 296 next = entry->next; 297 type = entry->event.type; 298 if (minType <= type && type <= maxType) { 299 events[used] = entry->event; 300 if (entry->event.type == SDL_SYSWMEVENT) { 301 /* We need to copy the wmmsg somewhere safe. 302 For now we'll guarantee it's valid at least until 303 the next call to SDL_PeepEvents() 304 */ 305 if (SDL_EventQ.wmmsg_free) { 306 wmmsg = SDL_EventQ.wmmsg_free; 307 SDL_EventQ.wmmsg_free = wmmsg->next; 308 } else { 309 wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg)); 310 } 311 wmmsg->msg = *entry->event.syswm.msg; 312 wmmsg->next = SDL_EventQ.wmmsg_used; 313 SDL_EventQ.wmmsg_used = wmmsg; 314 events[used].syswm.msg = &wmmsg->msg; 315 } 316 ++used; 317 318 if (action == SDL_GETEVENT) { 319 SDL_CutEvent(entry); 320 } 321 } 322 } 323 } 324 SDL_UnlockMutex(SDL_EventQ.lock); 325 } else { 326 return SDL_SetError("Couldn't lock event queue"); 327 } 328 return (used); 329} 330 331SDL_bool 332SDL_HasEvent(Uint32 type) 333{ 334 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type) > 0); 335} 336 337SDL_bool 338SDL_HasEvents(Uint32 minType, Uint32 maxType) 339{ 340 return (SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, minType, maxType) > 0); 341} 342 343void 344SDL_FlushEvent(Uint32 type) 345{ 346 SDL_FlushEvents(type, type); 347} 348 349void 350SDL_FlushEvents(Uint32 minType, Uint32 maxType) 351{ 352 /* Don't look after we've quit */ 353 if (!SDL_EventQ.active) { 354 return; 355 } 356 357 /* Make sure the events are current */ 358#if 0 359 /* Actually, we can't do this since we might be flushing while processing 360 a resize event, and calling this might trigger further resize events. 361 */ 362 SDL_PumpEvents(); 363#endif 364 365 /* Lock the event queue */ 366 if (SDL_LockMutex(SDL_EventQ.lock) == 0) { 367 SDL_EventEntry *entry, *next; 368 Uint32 type; 369 for (entry = SDL_EventQ.head; entry; entry = next) { 370 next = entry->next; 371 type = entry->event.type; 372 if (minType <= type && type <= maxType) { 373 SDL_CutEvent(entry); 374 } 375 } 376 SDL_UnlockMutex(SDL_EventQ.lock); 377 } 378} 379 380/* Run the system dependent event loops */ 381void 382SDL_PumpEvents(void) 383{ 384 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 385 386 /* Get events from the video subsystem */ 387 if (_this) { 388 _this->PumpEvents(_this); 389 } 390#if !SDL_JOYSTICK_DISABLED 391 /* Check for joystick state change */ 392 if ((!SDL_disabled_events[SDL_JOYAXISMOTION >> 8] || SDL_JoystickEventState(SDL_QUERY))) { 393 SDL_JoystickUpdate(); 394 } 395#endif 396} 397 398/* Public functions */ 399 400int 401SDL_PollEvent(SDL_Event * event) 402{ 403 return SDL_WaitEventTimeout(event, 0); 404} 405 406int 407SDL_WaitEvent(SDL_Event * event) 408{ 409 return SDL_WaitEventTimeout(event, -1); 410} 411 412int 413SDL_WaitEventTimeout(SDL_Event * event, int timeout) 414{ 415 Uint32 expiration = 0; 416 417 if (timeout > 0) 418 expiration = SDL_GetTicks() + timeout; 419 420 for (;;) { 421 SDL_PumpEvents(); 422 switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) { 423 case -1: 424 return 0; 425 case 1: 426 return 1; 427 case 0: 428 if (timeout == 0) { 429 /* Polling and no events, just return */ 430 return 0; 431 } 432 if (timeout > 0 && SDL_TICKS_PASSED(SDL_GetTicks(), expiration)) { 433 /* Timeout expired and no events */ 434 return 0; 435 } 436 SDL_Delay(10); 437 break; 438 } 439 } 440} 441 442int 443SDL_PushEvent(SDL_Event * event) 444{ 445 SDL_EventWatcher *curr; 446 447 event->common.timestamp = SDL_GetTicks(); 448 449 if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) { 450 return 0; 451 } 452 453 for (curr = SDL_event_watchers; curr; curr = curr->next) { 454 curr->callback(curr->userdata, event); 455 } 456 457 if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) { 458 return -1; 459 } 460 461 SDL_GestureProcessEvent(event); 462 463 return 1; 464} 465 466void 467SDL_SetEventFilter(SDL_EventFilter filter, void *userdata) 468{ 469 /* Set filter and discard pending events */ 470 SDL_EventOK = NULL; 471 SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT); 472 SDL_EventOKParam = userdata; 473 SDL_EventOK = filter; 474} 475 476SDL_bool 477SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata) 478{ 479 if (filter) { 480 *filter = SDL_EventOK; 481 } 482 if (userdata) { 483 *userdata = SDL_EventOKParam; 484 } 485 return SDL_EventOK ? SDL_TRUE : SDL_FALSE; 486} 487 488/* FIXME: This is not thread-safe yet */ 489void 490SDL_AddEventWatch(SDL_EventFilter filter, void *userdata) 491{ 492 SDL_EventWatcher *watcher, *tail; 493 494 watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher)); 495 if (!watcher) { 496 /* Uh oh... */ 497 return; 498 } 499 500 /* create the watcher */ 501 watcher->callback = filter; 502 watcher->userdata = userdata; 503 watcher->next = NULL; 504 505 /* add the watcher to the end of the list */ 506 if (SDL_event_watchers) { 507 for (tail = SDL_event_watchers; tail->next; tail = tail->next) { 508 continue; 509 } 510 tail->next = watcher; 511 } else { 512 SDL_event_watchers = watcher; 513 } 514} 515 516/* FIXME: This is not thread-safe yet */ 517void 518SDL_DelEventWatch(SDL_EventFilter filter, void *userdata) 519{ 520 SDL_EventWatcher *prev = NULL; 521 SDL_EventWatcher *curr; 522 523 for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) { 524 if (curr->callback == filter && curr->userdata == userdata) { 525 if (prev) { 526 prev->next = curr->next; 527 } else { 528 SDL_event_watchers = curr->next; 529 } 530 SDL_free(curr); 531 break; 532 } 533 } 534} 535 536void 537SDL_FilterEvents(SDL_EventFilter filter, void *userdata) 538{ 539 if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) { 540 SDL_EventEntry *entry, *next; 541 for (entry = SDL_EventQ.head; entry; entry = next) { 542 next = entry->next; 543 if (!filter(userdata, &entry->event)) { 544 SDL_CutEvent(entry); 545 } 546 } 547 SDL_UnlockMutex(SDL_EventQ.lock); 548 } 549} 550 551Uint8 552SDL_EventState(Uint32 type, int state) 553{ 554 Uint8 current_state; 555 Uint8 hi = ((type >> 8) & 0xff); 556 Uint8 lo = (type & 0xff); 557 558 if (SDL_disabled_events[hi] && 559 (SDL_disabled_events[hi]->bits[lo/32] & (1 << (lo&31)))) { 560 current_state = SDL_DISABLE; 561 } else { 562 current_state = SDL_ENABLE; 563 } 564 565 if (state != current_state) 566 { 567 switch (state) { 568 case SDL_DISABLE: 569 /* Disable this event type and discard pending events */ 570 if (!SDL_disabled_events[hi]) { 571 SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock)); 572 if (!SDL_disabled_events[hi]) { 573 /* Out of memory, nothing we can do... */ 574 break; 575 } 576 } 577 SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31)); 578 SDL_FlushEvent(type); 579 break; 580 case SDL_ENABLE: 581 SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31)); 582 break; 583 default: 584 /* Querying state... */ 585 break; 586 } 587 } 588 589 return current_state; 590} 591 592Uint32 593SDL_RegisterEvents(int numevents) 594{ 595 Uint32 event_base; 596 597 if ((numevents > 0) && (SDL_userevents+numevents <= SDL_LASTEVENT)) { 598 event_base = SDL_userevents; 599 SDL_userevents += numevents; 600 } else { 601 event_base = (Uint32)-1; 602 } 603 return event_base; 604} 605 606int 607SDL_SendAppEvent(SDL_EventType eventType) 608{ 609 int posted; 610 611 posted = 0; 612 if (SDL_GetEventState(eventType) == SDL_ENABLE) { 613 SDL_Event event; 614 event.type = eventType; 615 posted = (SDL_PushEvent(&event) > 0); 616 } 617 return (posted); 618} 619 620int 621SDL_SendSysWMEvent(SDL_SysWMmsg * message) 622{ 623 int posted; 624 625 posted = 0; 626 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) { 627 SDL_Event event; 628 SDL_memset(&event, 0, sizeof(event)); 629 event.type = SDL_SYSWMEVENT; 630 event.syswm.msg = message; 631 posted = (SDL_PushEvent(&event) > 0); 632 } 633 /* Update internal event state */ 634 return (posted); 635} 636 637/* vi: set ts=4 sw=4 expandtab: */